diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..25b312e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# http://editorconfig.org +root = true + +# 空格替代Tab缩进在各种编辑工具下效果一致 +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true + +[*.{json,yml,yaml}] +indent_size = 2 + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e33968 --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml new file mode 100644 index 0000000..03e7d1c --- /dev/null +++ b/.run/ruoyi-monitor-admin.run.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/.run/ruoyi-server.run.xml b/.run/ruoyi-server.run.xml new file mode 100644 index 0000000..a1670d9 --- /dev/null +++ b/.run/ruoyi-server.run.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/.run/ruoyi-xxl-job-admin.run.xml b/.run/ruoyi-xxl-job-admin.run.xml new file mode 100644 index 0000000..914ed01 --- /dev/null +++ b/.run/ruoyi-xxl-job-admin.run.xml @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..997d583 --- /dev/null +++ b/pom.xml @@ -0,0 +1,470 @@ + + + 4.0.0 + + com.zhi + ruoyi-vue-plus + 4.4.0 + + RuoYi-Vue-Plus + https://gitee.com/JavaLionLi/RuoYi-Vue-Plus + RuoYi-Vue-Plus后台管理系统 + + + 4.4.0 + 2.7.6 + UTF-8 + UTF-8 + 1.8 + 3.2.2 + 2.2.2 + 1.6.13 + 5.2.3 + 3.1.3 + 2.3 + 1.33.0 + 3.5.2 + 3.9.1 + 5.8.10 + 4.10.0 + 2.7.7 + 3.18.0 + 2.2.3 + 3.5.2 + 2.14.2 + 2.3.1 + 1.18.24 + 2.4.1 + 2.4.1 + 2.8.0 + 1.4.0 + 2.4.1 + 1.1.1 + + + + 31.1-jre + + 1.32 + + + 1.12.349 + + 2.0.22 + 3.1.635 + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + cn.hutool + hutool-bom + ${hutool.version} + pom + import + + + + org.springdoc + springdoc-openapi-webmvc-core + ${springdoc.version} + + + + org.springdoc + springdoc-openapi-javadoc + ${springdoc.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + com.alibaba + easyexcel + ${easyexcel.version} + + + org.apache.poi + poi-ooxml-schemas + + + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + cn.dev33 + sa-token-spring-boot-starter + ${satoken.version} + + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-all + + + + + + + com.baomidou + dynamic-datasource-spring-boot-starter + ${dynamic-ds.version} + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + com.baomidou + mybatis-plus-extension + ${mybatis-plus.version} + + + + p6spy + p6spy + ${p6spy.version} + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + + com.amazonaws + aws-java-sdk-s3 + ${aws-java-sdk-s3.version} + + + + com.aliyun + dysmsapi20170525 + ${aliyun.sms.version} + + + + com.tencentcloudapi + tencentcloud-sdk-java-sms + ${tencent.sms.version} + + + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + + + com.xuxueli + xxl-job-core + ${xxl-job.version} + + + + com.alibaba + transmittable-thread-local + ${alibaba-ttl.version} + + + + + com.google.guava + guava + ${guava.version} + + + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + + + com.zhi + zhi-job + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-generator + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-framework + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-system + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-common + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-oss + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-sms + ${zhi-vue-plus.version} + + + + + org.springframework.boot + spring-boot-starter-amqp + ${rabbitmq.version} + + + + org.springframework.boot + spring-boot-starter-mail + ${mail.version} + + + + + org.apache.commons + commons-pool2 + ${commons-pool2.version} + + + + + com.xkcoding.justauth + justauth-spring-boot-starter + ${justauth-spring-boot.version} + + + + org.springframework.boot + spring-boot-starter-websocket + ${websocket.version} + + + + + cn.easy-es + easy-es-boot-starter + ${easy-es.version} + + + + + + com.zhi + zhi-demo + ${zhi-vue-plus.version} + + + + + com.zhi + zhi-myblog + ${zhi-vue-plus.version} + + + + + + + zhi-admin + zhi-framework + zhi-system + zhi-job + zhi-generator + zhi-common + zhi-demo + zhi-extend + zhi-oss + zhi-sms + zhi-myblog + + pom + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + com.github.therapi + therapi-runtime-javadoc-scribe + 0.15.0 + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + -Dfile.encoding=UTF-8 + + ${profiles.active} + + exclude + + + + + + src/main/resources + + false + + + src/main/resources + + + application* + bootstrap* + banner* + + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + false + + + + + + + dev + + + dev + debug + + + + true + + + + + prod + + prod + warn + + + + + + + diff --git a/script/bin/ry.bat b/script/bin/ry.bat new file mode 100644 index 0000000..d57b79a --- /dev/null +++ b/script/bin/ry.bat @@ -0,0 +1,68 @@ +rem 使用者应根据自身平台编码自行转换 防止乱码 例如 win使用gbk编码 +@echo off + +rem jar平级目录 +set AppName=zhi-admin.jar + +rem JVM参数 +set JVM_OPTS="-Dname=%AppName% -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" + + +ECHO. + ECHO. [1] 启动%AppName% + ECHO. [2] 关闭%AppName% + ECHO. [3] 重启%AppName% + ECHO. [4] 启动状态 %AppName% + ECHO. [5] 退 出 +ECHO. + +ECHO.请输入选择项目的序号: +set /p ID= + IF "%id%"=="1" GOTO start + IF "%id%"=="2" GOTO stop + IF "%id%"=="3" GOTO restart + IF "%id%"=="4" GOTO status + IF "%id%"=="5" EXIT +PAUSE +:start + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if defined pid ( + echo %%is running + PAUSE + ) + +start javaw %JVM_OPTS% -jar %AppName% + +echo starting…… +echo Start %AppName% success... +goto:eof + +rem 函数stop通过jps命令查找pid并结束进程 +:stop + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% does not exists) else ( + echo prepare to kill %image_name% + echo start kill %pid% ... + rem 根据进程ID,kill进程 + taskkill /f /pid %pid% + ) +goto:eof +:restart + call :stop + call :start +goto:eof +:status + for /f "usebackq tokens=1-2" %%a in (`jps -l ^| findstr %AppName%`) do ( + set pid=%%a + set image_name=%%b + ) + if not defined pid (echo process %AppName% is dead ) else ( + echo %image_name% is running + ) +goto:eof diff --git a/script/bin/ry.sh b/script/bin/ry.sh new file mode 100644 index 0000000..aa9b62b --- /dev/null +++ b/script/bin/ry.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# ./ry.sh start 启动 stop 停止 restart 重启 status 状态 +AppName=zhi-admin.jar + +# JVM参数 +JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC" +APP_HOME=`pwd` +LOG_PATH=$APP_HOME/logs/$AppName.log + +if [ "$1" = "" ]; +then + echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m" + exit 1 +fi + +if [ "$AppName" = "" ]; +then + echo -e "\033[0;31m 未输入应用名 \033[0m" + exit 1 +fi + +function start() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + + if [ x"$PID" != x"" ]; then + echo "$AppName is running..." + else + nohup java $JVM_OPTS -jar $AppName > /dev/null 2>&1 & + echo "Start $AppName success..." + fi +} + +function stop() +{ + echo "Stop $AppName" + + PID="" + query(){ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'` + } + + query + if [ x"$PID" != x"" ]; then + kill -TERM $PID + echo "$AppName (pid:$PID) exiting..." + while [ x"$PID" != x"" ] + do + sleep 1 + query + done + echo "$AppName exited." + else + echo "$AppName already stopped." + fi +} + +function restart() +{ + stop + sleep 2 + start +} + +function status() +{ + PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l` + if [ $PID != 0 ];then + echo "$AppName is running..." + else + echo "$AppName is not running..." + fi +} + +case $1 in + start) + start;; + stop) + stop;; + restart) + restart;; + status) + status;; + *) + +esac diff --git a/script/docker/database.yml b/script/docker/database.yml new file mode 100644 index 0000000..0368fd2 --- /dev/null +++ b/script/docker/database.yml @@ -0,0 +1,61 @@ +version: '3' + +services: + # 此镜像仅用于测试 正式环境需自行安装数据库 + # SID: XE user: system password: oracle + oracle: + image: tekintian/oracle12c:latest + container_name: oracle + environment: + # 时区上海 + TZ: Asia/Shanghai + DBCA_TOTAL_MEMORY: 16192 + ports: + - "18080:8080" + - "1521:1521" + volumes: + # 数据挂载 + - "/docker/oracle/data:/u01/app/oracle" + network_mode: "host" + + # 此镜像仅用于测试 正式环境需自行安装数据库 + sqlserver: + image: mcr.microsoft.com/mssql/server:2017-latest + container_name: sqlserver + environment: + # 时区上海 + TZ: Asia/Shanghai + ACCEPT_EULA: "Y" + SA_PASSWORD: "Ruoyi@123" + ports: + - "1433:1433" + volumes: + # 数据挂载 + - "/docker/sqlserver/data:/var/opt/mssql" + network_mode: "host" + + postgres: + image: postgres:14.2 + container_name: postgres + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5432:5432" + volumes: + - /docker/postgres/data:/var/lib/postgresql/data + network_mode: "host" + + postgres13: + image: postgres:13.6 + container_name: postgres13 + environment: + POSTGRES_USER: root + POSTGRES_PASSWORD: root + POSTGRES_DB: postgres + ports: + - "5433:5432" + volumes: + - /docker/postgres13/data:/var/lib/postgresql/data + network_mode: "host" diff --git a/script/docker/docker-compose.yml b/script/docker/docker-compose.yml new file mode 100644 index 0000000..b31f2a3 --- /dev/null +++ b/script/docker/docker-compose.yml @@ -0,0 +1,154 @@ +version: '3' + +services: + mysql: + image: mysql:8.0.31 + 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: + # 将mysql8.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 + network_mode: "host" + + nginx-web: + image: nginx:1.22.1 + container_name: nginx-web + environment: + # 时区上海 + TZ: Asia/Shanghai + 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 + privileged: true + network_mode: "host" + + redis: + image: redis:6.2.7 + container_name: redis + ports: + - "6379:6379" + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/redis/conf:/redis/config:rw + # 数据文件 + - /docker/redis/data/:/redis/data/:rw + command: "redis-server /redis/config/redis.conf" + privileged: true + network_mode: "host" + + minio: + image: minio/minio:RELEASE.2022-05-26T05-48-41Z + container_name: minio + ports: + # api 端口 + - "9000:9000" + # 控制台端口 + - "9001:9001" + environment: + # 时区上海 + TZ: Asia/Shanghai + # 管理后台用户名 + MINIO_ACCESS_KEY: ruoyi + # 管理后台密码,最小8个字符 + MINIO_SECRET_KEY: ruoyi123 + # https需要指定域名 + #MINIO_SERVER_URL: "https://xxx.com:9000" + #MINIO_BROWSER_REDIRECT_URL: "https://xxx.com:9001" + # 开启压缩 on 开启 off 关闭 + MINIO_COMPRESS: "off" + # 扩展名 .pdf,.doc 为空 所有类型均压缩 + MINIO_COMPRESS_EXTENSIONS: "" + # mime 类型 application/pdf 为空 所有类型均压缩 + MINIO_COMPRESS_MIME_TYPES: "" + volumes: + # 映射当前目录下的data目录至容器内/data目录 + - /docker/minio/data:/data + # 映射配置目录 + - /docker/minio/config:/root/.minio/ + command: server --address ':9000' --console-address ':9001' /data # 指定容器中的目录 /data + privileged: true + network_mode: "host" + + ruoyi-server1: + image: ruoyi/ruoyi-server:4.4.0 + container_name: ruoyi-server1 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8080 + volumes: + # 配置文件 + - /docker/server1/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + ruoyi-server2: + image: "ruoyi/ruoyi-server:4.4.0" + container_name: ruoyi-server2 + environment: + # 时区上海 + TZ: Asia/Shanghai + SERVER_PORT: 8081 + volumes: + # 配置文件 + - /docker/server2/logs/:/ruoyi/server/logs/ + # skywalking 探针 +# - /docker/skywalking/agent/:/ruoyi/skywalking/agent + privileged: true + network_mode: "host" + + zhi-monitor-admin: + image: ruoyi/zhi-monitor-admin:4.4.0 + container_name: zhi-monitor-admin + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/monitor/logs/:/ruoyi/monitor/logs + privileged: true + network_mode: "host" + + zhi-xxl-job-admin: + image: ruoyi/zhi-xxl-job-admin:4.4.0 + container_name: zhi-xxl-job-admin + environment: + # 时区上海 + TZ: Asia/Shanghai + volumes: + # 配置文件 + - /docker/xxljob/logs/:/ruoyi/xxljob/logs + privileged: true + network_mode: "host" diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf new file mode 100644 index 0000000..e9630aa --- /dev/null +++ b/script/docker/nginx/conf/nginx.conf @@ -0,0 +1,111 @@ +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 { + ip_hash; + server 127.0.0.1:8080; + server 127.0.0.1:8081; + } + + upstream monitor-admin { + server 127.0.0.1:9090; + } + + upstream xxljob-admin { + server 127.0.0.1:9100; + } + + 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/ 为docker映射路径 不允许更改 + #ssl_certificate_key /etc/nginx/cert/xxx.local.key; # /etc/nginx/cert/ 为docker映射路径 不允许更改 + #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 + + # 演示环境配置 拦截除 GET POST 之外的所有请求 + # if ($request_method !~* GET|POST) { + # rewrite ^/(.*)$ /403; + # } + + # location = /403 { + # default_type application/json; + # return 200 '{"msg":"演示模式,不允许操作","code":500}'; + # } + + # 限制外网访问内网 actuator 相关路径 + location ~ ^(/[^/]*)?/actuator(/.*)?$ { + return 403; + } + + 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/; + } + + # https 会拦截内链所有的 http 请求 造成功能无法使用 + # 解决方案1 将 admin 服务 也配置成 https + # 解决方案2 将菜单配置为外链访问 走独立页面 http 访问 + 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/; + } + + # https 会拦截内链所有的 http 请求 造成功能无法使用 + # 解决方案1 将 xxljob 服务 也配置成 https + # 解决方案2 将菜单配置为外链访问 走独立页面 http 访问 + location /xxl-job-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://xxljob-admin/xxl-job-admin/; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root html; + } + } +} diff --git a/script/docker/redis/conf/redis.conf b/script/docker/redis/conf/redis.conf new file mode 100644 index 0000000..8ac7da0 --- /dev/null +++ b/script/docker/redis/conf/redis.conf @@ -0,0 +1,28 @@ +# redis 密码 +requirepass ruoyi123 + +# key 监听器配置 +# notify-keyspace-events Ex + +# 配置持久化文件存储路径 +dir /redis/data +# 配置rdb +# 15分钟内有至少1个key被更改则进行快照 +save 900 1 +# 5分钟内有至少10个key被更改则进行快照 +save 300 10 +# 1分钟内有至少10000个key被更改则进行快照 +save 60 10000 +# 开启压缩 +rdbcompression yes +# rdb文件名 用默认的即可 +dbfilename dump.rdb + +# 开启aof +appendonly yes +# 文件名 +appendfilename "appendonly.aof" +# 持久化策略,no:不同步,everysec:每秒一次,always:总是同步,速度比较慢 +# appendfsync always +appendfsync everysec +# appendfsync no diff --git a/script/docker/redis/data/README.md b/script/docker/redis/data/README.md new file mode 100644 index 0000000..fbc5474 --- /dev/null +++ b/script/docker/redis/data/README.md @@ -0,0 +1 @@ +数据目录 请执行 `chmod 777 /docker/redis/data` 赋予读写权限 否则将无法写入数据 \ No newline at end of file diff --git a/script/sql/ry-vue-blog.sql b/script/sql/ry-vue-blog.sql new file mode 100644 index 0000000..ba27f7e --- /dev/null +++ b/script/sql/ry-vue-blog.sql @@ -0,0 +1,2954 @@ +/* + Navicat Premium Data Transfer + + Source Server : 本地电脑 + Source Server Type : MySQL + Source Server Version : 80017 (8.0.17) + Source Host : localhost:3306 + Source Schema : ry-vue-blog + + Target Server Type : MySQL + Target Server Version : 80017 (8.0.17) + File Encoding : 65001 + + Date: 17/04/2023 19:09:06 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for blog_article +-- ---------------------------- +DROP TABLE IF EXISTS `blog_article`; +CREATE TABLE `blog_article` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT, + `user_id` bigint(11) NOT NULL COMMENT '作者', + `category_id` int(11) NULL DEFAULT NULL COMMENT '文章分类', + `article_cover` bigint(20) NULL DEFAULT NULL COMMENT '文章缩略图', + `article_title` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '标题', + `article_content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '内容', + `type` tinyint(1) NOT NULL DEFAULT 0 COMMENT '文章类型 1原创 2转载 3翻译', + `original_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '原文链接', + `is_top` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否置顶 0否 1是', + `is_delete` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除 0否 1是', + `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态值 1公开 2私密 3评论可见', + `create_time` datetime NOT NULL COMMENT '发表时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `like_count` int(11) NULL DEFAULT 0 COMMENT '点赞数', + `views_count` int(11) NULL DEFAULT 0 COMMENT '浏览量', + `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + FULLTEXT INDEX `ft_search`(`article_content`) +) ENGINE = InnoDB AUTO_INCREMENT = 158 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_article +-- ---------------------------- +INSERT INTO `blog_article` VALUES (143, 1, 214, 1647487717082169345, '新的vue测试', '# Vue中 this.$router.push 传参 及 参数接收\n@[TOC](文章目录)\n## 1:两种方式![Description](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\n### 方法一:name跳转页面\n\n```js\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\n\n```\n**另一页面接收参数方式:**\n![1161451.jpg](http://127.0.0.1:9000/blog/2023/04/17/c45820d458654545b92c79c6fd148311.jpg)\n```js\nthis.$route.params.id\n\n```\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\n控制台展示:\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\n### 方法二:path跳转页面\n\n```js\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\n\n```\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\n\n\n## 2、区别\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\n\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779', 1, NULL, 0, 0, 1, '2023-01-13 19:45:57', '2023-04-17 18:34:46', 0, 0, 'admin', 'admin'); +INSERT INTO `blog_article` VALUES (156, 1, 1, 1630396074092933122, '123', '123', 1, NULL, 0, 0, 1, '2023-02-28 10:34:52', '2023-02-28 11:29:54', 0, 0, 'admin', 'admin'); +INSERT INTO `blog_article` VALUES (157, 1, 1, 1647910881729728513, '喜好测试', '喜好测试', 1, NULL, 0, 0, 1, '2023-04-17 18:32:28', '2023-04-17 18:32:28', 0, 0, 'admin', 'admin'); + +-- ---------------------------- +-- Table structure for blog_article_tag +-- ---------------------------- +DROP TABLE IF EXISTS `blog_article_tag`; +CREATE TABLE `blog_article_tag` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `article_id` int(11) NOT NULL COMMENT '文章id', + `tag_id` int(11) NOT NULL COMMENT '标签id', + PRIMARY KEY (`id`) USING BTREE, + INDEX `fk_article_tag_1`(`article_id` ASC) USING BTREE, + INDEX `fk_article_tag_2`(`tag_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1220 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_article_tag +-- ---------------------------- +INSERT INTO `blog_article_tag` VALUES (1211, 156, 1); +INSERT INTO `blog_article_tag` VALUES (1218, 157, 1); +INSERT INTO `blog_article_tag` VALUES (1219, 143, 66); + +-- ---------------------------- +-- Table structure for blog_category +-- ---------------------------- +DROP TABLE IF EXISTS `blog_category`; +CREATE TABLE `blog_category` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT, + `category_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '分类名', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人', + `update_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新用户', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 228 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_category +-- ---------------------------- +INSERT INTO `blog_category` VALUES (1, '默认', '2023-02-16 14:07:57', '2023-02-16 14:07:57', 'admin', 'admin'); +INSERT INTO `blog_category` VALUES (214, '测试', '2022-11-24 20:34:23', '2023-01-07 14:48:28', NULL, 'admin'); +INSERT INTO `blog_category` VALUES (216, '正式', '2023-01-08 19:02:14', '2023-01-09 11:27:26', 'admin', 'admin'); +INSERT INTO `blog_category` VALUES (217, '付费', '2023-01-08 20:28:59', '2023-01-09 11:27:52', 'admin', 'admin'); +INSERT INTO `blog_category` VALUES (218, '积分', '2023-01-08 21:23:52', '2023-01-09 11:27:57', 'admin', 'admin'); + +-- ---------------------------- +-- Table structure for blog_chat_record +-- ---------------------------- +DROP TABLE IF EXISTS `blog_chat_record`; +CREATE TABLE `blog_chat_record` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` bigint(11) NULL DEFAULT NULL COMMENT '用户id', + `nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '昵称', + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头像', + `content` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '聊天内容', + `ip_address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'ip地址', + `ip_source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'ip来源', + `type` tinyint(4) NOT NULL COMMENT '类型', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3049 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_chat_record +-- ---------------------------- +INSERT INTO `blog_chat_record` VALUES (1, 1, 'admin', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '你好', '127.0.0.1', '127.0.0.1', 1, '2023-02-28 17:16:49', '2023-01-02 17:16:56'); +INSERT INTO `blog_chat_record` VALUES (2991, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '666', NULL, NULL, 3, '2023-03-09 17:59:16', NULL); +INSERT INTO `blog_chat_record` VALUES (2995, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '💥', NULL, NULL, 3, '2023-03-09 18:06:51', NULL); +INSERT INTO `blog_chat_record` VALUES (3018, 0, '游客', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '666', NULL, NULL, 3, '2023-03-10 17:31:05', NULL); +INSERT INTO `blog_chat_record` VALUES (3019, 0, '游客', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '💗', NULL, NULL, 3, '2023-03-10 17:31:27', NULL); +INSERT INTO `blog_chat_record` VALUES (3020, 0, '游客', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '💘', NULL, NULL, 3, '2023-03-10 17:35:32', NULL); +INSERT INTO `blog_chat_record` VALUES (3021, 0, '游客', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '🥰', NULL, NULL, 3, '2023-03-10 17:38:31', NULL); +INSERT INTO `blog_chat_record` VALUES (3022, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '999', NULL, NULL, 3, '2023-03-10 17:51:01', NULL); +INSERT INTO `blog_chat_record` VALUES (3023, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', 'http://127.0.0.1:9000/blog/2023/03/10/80220840d3ad4464b985a570af567bcc.wav', 'undefined', 'undefined', 5, '2023-03-10 18:00:15', NULL); +INSERT INTO `blog_chat_record` VALUES (3024, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', 'http://127.0.0.1:9000/blog/2023/03/10/87e3915623a44d4cbdd9a6500c96bddb.wav', 'undefined', 'undefined', 5, '2023-03-10 18:02:39', NULL); +INSERT INTO `blog_chat_record` VALUES (3025, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', 'http://127.0.0.1:9000/blog/2023/03/10/770cb001c77640019d594a9373910792.wav', 'undefined', 'undefined', 5, '2023-03-10 18:02:58', NULL); +INSERT INTO `blog_chat_record` VALUES (3026, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', 'http://127.0.0.1:9000/blog/2023/03/10/a8f56f0433c9416ba42322d38a9e8d64.wav', 'undefined', 'undefined', 5, '2023-03-10 18:03:59', NULL); +INSERT INTO `blog_chat_record` VALUES (3027, 0, '游客', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '33', NULL, NULL, 3, '2023-03-11 13:17:14', NULL); +INSERT INTO `blog_chat_record` VALUES (3028, 0, '未知ip', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '哈喽', '未知ip', '', 3, '2023-03-11 13:19:24', NULL); +INSERT INTO `blog_chat_record` VALUES (3029, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '你是谁', '未知ip', '', 3, '2023-03-11 13:19:59', NULL); +INSERT INTO `blog_chat_record` VALUES (3030, 0, '未知ip', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '嗯嗯?', '未知ip', '', 3, '2023-03-11 13:20:05', NULL); +INSERT INTO `blog_chat_record` VALUES (3031, 3, '本部门及以下 密码666666', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '789', '6666', '6666', 3, '2023-03-11 13:25:59', NULL); +INSERT INTO `blog_chat_record` VALUES (3032, 3, '本部门及以下 密码666666', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '6', '未知ip', '', 3, '2023-03-11 13:37:14', NULL); +INSERT INTO `blog_chat_record` VALUES (3033, 3, '本部门及以下 密码666666', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '456', '127.0.0.1:8080', '', 3, '2023-03-11 13:40:20', NULL); +INSERT INTO `blog_chat_record` VALUES (3034, 3, '本部门及以下 密码666666', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '999', '127.0.0.1:8080', '', 3, '2023-03-11 13:40:35', NULL); +INSERT INTO `blog_chat_record` VALUES (3035, 3, '本部门及以下 密码666666', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '亲爱的', '127.0.0.1', '内网IP', 3, '2023-03-11 13:45:08', NULL); +INSERT INTO `blog_chat_record` VALUES (3036, 0, '127.0.0.1', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', 'wa', '127.0.0.1', '内网IP', 3, '2023-03-11 14:41:36', NULL); +INSERT INTO `blog_chat_record` VALUES (3037, 0, '127.0.0.1', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '为什么', '127.0.0.1', '内网IP', 3, '2023-03-11 16:19:35', NULL); +INSERT INTO `blog_chat_record` VALUES (3038, 0, '', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '3', '', '', 3, '2023-03-11 16:54:13', NULL); +INSERT INTO `blog_chat_record` VALUES (3039, NULL, '127.0.0.1', 'null', 'http://127.0.0.1:9000/blog/2023/03/11/8dbac03922f24a07bce8f0c28e540e47.wav', '127.0.0.1', '内网IP', 5, '2023-03-11 17:16:27', NULL); +INSERT INTO `blog_chat_record` VALUES (3040, NULL, '127.0.0.1', 'null', 'http://127.0.0.1:9000/blog/2023/03/11/5310f49688eb4434bd40ce031b471230.wav', '127.0.0.1', '内网IP', 5, '2023-03-11 17:16:57', NULL); +INSERT INTO `blog_chat_record` VALUES (3041, NULL, '127.0.0.1', 'null', 'http://127.0.0.1:9000/blog/2023/03/11/59e254468a49495b8186a57bb5c60733.wav', '127.0.0.1', '内网IP', 5, '2023-03-11 17:18:27', NULL); +INSERT INTO `blog_chat_record` VALUES (3042, 0, '0:0:0:0:0:0:0:1', 'http://8.130.45.202:9000/blog/2023/02/23/c944a0b16c5346d4a81525ae5841f698.jpg', '?', '0:0:0:0:0:0:0:1', '内网IP', 3, '2023-03-11 17:25:26', NULL); +INSERT INTO `blog_chat_record` VALUES (3043, NULL, '127.0.0.1', 'null', 'http://127.0.0.1:9000/blog/2023/03/11/ad5d9e1848b6497cb2d50e100103908a.wav', '127.0.0.1', '内网IP', 5, '2023-03-11 17:33:43', NULL); +INSERT INTO `blog_chat_record` VALUES (3044, 0, '127.0.0.1', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '33', '127.0.0.1', '内网IP', 3, '2023-03-12 12:34:03', NULL); +INSERT INTO `blog_chat_record` VALUES (3045, 0, '127.0.0.1', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '💗💥', '127.0.0.1', '内网IP', 3, '2023-03-12 14:56:50', NULL); +INSERT INTO `blog_chat_record` VALUES (3046, 0, '127.0.0.1', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '💯🤡123😃', '127.0.0.1', '内网IP', 3, '2023-03-12 15:01:27', NULL); +INSERT INTO `blog_chat_record` VALUES (3047, 0, '127.0.0.1', 'https://s1.ax1x.com/2023/03/09/ppndcTJ.png', '123123💯🤡😆', '127.0.0.1', '内网IP', 3, '2023-03-12 15:05:31', NULL); +INSERT INTO `blog_chat_record` VALUES (3048, 1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '666', '127.0.0.1', '内网IP', 3, '2023-04-17 19:06:33', NULL); + +-- ---------------------------- +-- Table structure for blog_comment +-- ---------------------------- +DROP TABLE IF EXISTS `blog_comment`; +CREATE TABLE `blog_comment` ( + `id` bigint(30) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` bigint(30) NOT NULL COMMENT '评论用户Id', + `comment_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '评论内容', + `reply_user_id` bigint(30) NULL DEFAULT NULL COMMENT '回复用户id', + `parent_id` bigint(11) NULL DEFAULT NULL COMMENT '父评论id', + `type` tinyint(4) NOT NULL COMMENT '评论类型 1.文章 2.友链 3.说说', + `is_delete` tinyint(4) NOT NULL DEFAULT 0 COMMENT '是否删除 0否 1是', + `create_time` datetime NOT NULL COMMENT '评论时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `topic_id` int(11) NULL DEFAULT NULL COMMENT '评论主题id', + `ip_address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '评论ip', + `ip_source` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '真实地址', + `state` int(10) NULL DEFAULT NULL COMMENT '评论状态', + `create_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `fk_comment_user`(`user_id` ASC) USING BTREE, + INDEX `fk_comment_parent`(`parent_id` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1614588562538348562 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_comment +-- ---------------------------- +INSERT INTO `blog_comment` VALUES (1, 1, '测试评论说说', NULL, NULL, 3, 0, '2022-12-07 19:35:07', NULL, 50, '192.168.88.111', '本地局域网', 1, 'admin', 'admin'); +INSERT INTO `blog_comment` VALUES (2, 1, '测试评论说说2', NULL, NULL, 3, 0, '2023-01-14 14:36:05', NULL, 50, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (3, 1, '测试回复说说', 1, 1, 3, 0, '2022-03-11 22:52:32', '2022-03-11 22:52:32', 50, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (4, 1, '测试评论文章', NULL, NULL, 1, 0, '2023-01-14 17:45:37', NULL, 138, NULL, NULL, 1, 'admin', NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348546, 1614548939325845505, '啦啦啦', NULL, NULL, 1, 0, '2023-01-15 19:41:26', '2023-01-15 19:41:26', 143, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348549, 1, '好滴好滴', NULL, NULL, 3, 0, '2023-01-15 19:54:28', '2023-01-15 19:54:28', 51, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348550, 1, '好滴', NULL, NULL, 3, 0, '2023-01-15 19:54:36', '2023-01-15 19:54:36', 51, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348551, 1, '哈哈哈', NULL, NULL, 3, 0, '2023-01-15 19:55:10', '2023-01-15 19:55:10', 51, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348552, 1, '回复说说哦', 1, 1614588562538348551, 3, 0, '2023-01-15 19:55:18', '2023-01-15 19:55:18', 51, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348553, 1614548939325845505, '拜拜', 1, 1614588562538348547, 1, 0, '2023-01-15 19:57:37', '2023-01-15 19:57:37', 143, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348554, 1614548939325845505, '啦啦啦', NULL, NULL, 1, 0, '2023-01-15 19:59:31', '2023-01-15 19:59:31', 139, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348555, 1614548939325845505, '123123', NULL, NULL, 2, 0, '2023-01-17 12:12:30', '2023-01-17 12:12:30', NULL, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348556, 1, '😁😆', NULL, NULL, 1, 0, '2023-02-09 20:11:50', '2023-02-09 20:11:50', 143, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348557, 1, '333', NULL, NULL, 1, 0, '2023-02-27 20:50:40', '2023-02-27 20:50:40', 139, NULL, NULL, 1, NULL, NULL); +INSERT INTO `blog_comment` VALUES (1614588562538348561, 1, '删除删除', NULL, NULL, 2, 0, '2023-02-28 20:18:01', '2023-02-28 20:18:01', NULL, NULL, NULL, 2, NULL, NULL); + +-- ---------------------------- +-- Table structure for blog_friend_link +-- ---------------------------- +DROP TABLE IF EXISTS `blog_friend_link`; +CREATE TABLE `blog_friend_link` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT, + `link_name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '链接名', + `link_avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '链接头像', + `link_address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '链接地址', + `link_intro` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '链接介绍', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `fk_friend_link_user`(`link_name` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 41 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_friend_link +-- ---------------------------- +INSERT INTO `blog_friend_link` VALUES (1, '风丶宇的个人博客', 'https://static.talkxj.com/photos/b553f564f81a80dc338695acb1b475d2.jpg', 'https://www.talkxj.com', '往事不随风', '2022-01-18 00:26:46', NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for blog_message +-- ---------------------------- +DROP TABLE IF EXISTS `blog_message`; +CREATE TABLE `blog_message` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '昵称', + `avatar` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '头像', + `message_content` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '留言内容', + `ip_address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户ip', + `ip_source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户地址', + `time` tinyint(1) NULL DEFAULT NULL COMMENT '弹幕速度', + `is_review` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '1' COMMENT '是否审核', + `create_time` datetime NOT NULL COMMENT '发布时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '修改时间', + `create_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 3948 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_message +-- ---------------------------- +INSERT INTO `blog_message` VALUES (1, 'water-之', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '测试留言', '127.0.0.1', NULL, 10, 'Y', '2023-01-20 16:52:48', '2023-01-14 21:31:42', NULL, 'admin'); +INSERT INTO `blog_message` VALUES (3946, '老爸', 'https://s1.ax1x.com/2023/01/15/pSQf91A.jpg', '123123', '127.0.0.1', '', 9, 'N', '2023-01-15 21:07:59', '2023-01-15 21:07:59', NULL, NULL); +INSERT INTO `blog_message` VALUES (3947, '游客', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/d917e0eddca44f41ba8e4befd51758c6.jpg', '123', '4.2.2.2', '美国', 7, 'Y', '2023-02-17 16:34:21', '2023-02-17 16:34:21', NULL, NULL); + +-- ---------------------------- +-- Table structure for blog_operation_log +-- ---------------------------- +DROP TABLE IF EXISTS `blog_operation_log`; +CREATE TABLE `blog_operation_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', + `opt_module` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作模块', + `opt_type` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作类型', + `opt_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作url', + `opt_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作方法', + `opt_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作描述', + `request_param` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '请求参数', + `request_method` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '请求方式', + `response_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '返回数据', + `user_id` int(11) NOT NULL COMMENT '用户id', + `nickname` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户昵称', + `ip_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作ip', + `ip_source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '操作地址', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1529 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_operation_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for blog_page +-- ---------------------------- +DROP TABLE IF EXISTS `blog_page`; +CREATE TABLE `blog_page` ( + `id` bigint(30) NOT NULL AUTO_INCREMENT COMMENT '页面id', + `page_name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '页面名', + `page_label` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '页面标签', + `page_cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '页面封面', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 905 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '页面' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_page +-- ---------------------------- +INSERT INTO `blog_page` VALUES (1, '首页', 'home', '1647487957390622721', '2021-08-07 10:32:36', '2023-04-16 14:31:53', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (2, '归档', 'archive', '1614606077834403841', '2021-08-07 10:32:36', '2023-01-15 20:51:03', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (3, '分类', 'category', '1614606235632508930', '2021-08-07 10:32:36', '2023-01-15 20:51:42', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (4, '标签', 'tag', '1614606349667246081', '2021-08-07 10:32:36', '2023-01-15 20:52:09', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (5, '相册', 'album', 'http://localhost:8080/upload/config/宇宙.jpg', '2021-08-07 10:32:36', '2021-12-27 12:23:12', NULL, NULL); +INSERT INTO `blog_page` VALUES (6, '友链', 'link', '1614606607352700929', '2021-08-07 10:32:36', '2023-01-15 20:53:12', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (7, '关于', 'about', '1614610913900367873', '2021-08-07 10:32:36', '2023-01-15 21:10:16', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (8, '留言', 'message', '1614251029958778882', '2021-08-07 10:32:36', '2023-01-14 21:20:15', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (9, '个人中心', 'user', '1614606431695249409', '2021-08-07 10:32:36', '2023-01-15 20:52:29', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (10, '文章列表', 'articleList', '1614606523919605761', '2021-08-10 15:36:19', '2023-01-15 20:52:53', NULL, 'admin'); +INSERT INTO `blog_page` VALUES (11, '说说', 'talk', '1614607161785163778', '2022-01-23 00:51:24', '2023-01-15 20:55:22', NULL, 'admin'); + +-- ---------------------------- +-- Table structure for blog_photo +-- ---------------------------- +DROP TABLE IF EXISTS `blog_photo`; +CREATE TABLE `blog_photo` ( + `id` bigint(30) NOT NULL AUTO_INCREMENT COMMENT '主键', + `album_id` bigint(30) NOT NULL COMMENT '相册id', + `photo_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '照片名', + `photo_desc` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '照片描述', + `photo_src` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '照片地址', + `is_delete` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1633693831616565251 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '照片' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_photo +-- ---------------------------- +INSERT INTO `blog_photo` VALUES (1633693831616565250, 1630182639979831298, 'LOL娜美3440x1440壁纸_千叶网.jpeg', NULL, 'http://127.0.0.1:9000/blog/2023/03/09/bf0032f388f249cd8d47b81ed24a26a4.jpeg', 0, '2023-03-09 12:58:57', '2023-03-09 12:58:57', 'admin', 'admin'); + +-- ---------------------------- +-- Table structure for blog_photo_album +-- ---------------------------- +DROP TABLE IF EXISTS `blog_photo_album`; +CREATE TABLE `blog_photo_album` ( + `id` bigint(30) NOT NULL AUTO_INCREMENT COMMENT '主键', + `album_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '相册名', + `album_desc` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '相册描述', + `album_cover` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '相册封面', + `is_delete` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否删除', + `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态值 1公开 2私密', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1630182639979831299 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '相册' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_photo_album +-- ---------------------------- +INSERT INTO `blog_photo_album` VALUES (1630182639979831298, '测试', '测试', 'http://127.0.0.1:9000/blog/2023/02/27/c1ed44bc66de4d648209d14b9d31bd69.jpg', 0, 1, '2023-02-27 20:26:43', '2023-02-27 20:26:43', 'admin', 'admin'); + +-- ---------------------------- +-- Table structure for blog_tag +-- ---------------------------- +DROP TABLE IF EXISTS `blog_tag`; +CREATE TABLE `blog_tag` ( + `id` bigint(11) NOT NULL AUTO_INCREMENT, + `tag_name` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '标签名', + `create_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `create_time` datetime NULL DEFAULT NULL, + `update_by` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 68 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of blog_tag +-- ---------------------------- +INSERT INTO `blog_tag` VALUES (1, '默认', 'admin', '2023-02-16 13:42:39', 'admin', '2023-02-16 14:12:43'); +INSERT INTO `blog_tag` VALUES (54, '测试', NULL, NULL, 'admin', '2023-01-08 15:01:53'); +INSERT INTO `blog_tag` VALUES (55, 'vue', 'admin', '2023-01-09 11:44:46', 'admin', '2023-01-09 11:44:46'); +INSERT INTO `blog_tag` VALUES (56, 'springboot', 'admin', '2023-01-09 11:44:54', 'admin', '2023-01-09 11:44:54'); +INSERT INTO `blog_tag` VALUES (59, 'html', 'admin', '2023-01-09 21:13:58', 'admin', '2023-01-09 21:13:58'); +INSERT INTO `blog_tag` VALUES (66, '啦啦啦', 'admin', '2023-01-16 14:20:51', 'admin', '2023-01-16 14:20:51'); + +-- ---------------------------- +-- Table structure for blog_talk +-- ---------------------------- +DROP TABLE IF EXISTS `blog_talk`; +CREATE TABLE `blog_talk` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '说说id', + `user_id` int(11) NOT NULL COMMENT '用户id', + `content` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '说说内容', + `images` varchar(2500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图片', + `is_top` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否置顶', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `create_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + `update_by` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 60 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_talk +-- ---------------------------- +INSERT INTO `blog_talk` VALUES (52, 1, '😀😃😂', NULL, 0, '2023-02-08 22:24:16', '2023-02-08 22:24:16', 'admin', 'admin'); +INSERT INTO `blog_talk` VALUES (54, 1, '😄 😆😉🙂', NULL, 0, '2023-02-08 22:47:21', '2023-02-16 14:18:32', 'admin', 'admin'); +INSERT INTO `blog_talk` VALUES (55, 1, '😁😆', NULL, 0, '2023-02-15 21:08:07', '2023-02-16 14:19:26', 'admin', 'admin'); + +-- ---------------------------- +-- Table structure for blog_website_config +-- ---------------------------- +DROP TABLE IF EXISTS `blog_website_config`; +CREATE TABLE `blog_website_config` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `config` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '配置信息', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of blog_website_config +-- ---------------------------- +INSERT INTO `blog_website_config` VALUES (1, '{\"alipayQRCode\":\"1613170158132543490\",\"gitee\":\"https://gitee.com/kalashok-pan\",\"github\":\"\",\"isChatRoom\":1,\"isCommentReview\":1,\"isEmailNotice\":1,\"isMessageReview\":1,\"isMusicPlayer\":0,\"isReward\":1,\"qq\":\"2831826106\",\"socialLoginList\":[\"qq\",\"weibo\",\"gitee\"],\"socialUrlList\":[\"gitee\",\"qq\"],\"touristAvatar\":\"1613170094936965121\",\"userAvatar\":\"1613170007087267841\",\"websiteAuthor\":\"Water-之\",\"websiteAvatar\":\"1625787929773232129\",\"websiteCreateTime\":\"2023-02-22\",\"websiteIntro\":\"记录成长\",\"websiteName\":\"夜色\",\"websiteNotice\":\"欢迎来到我的博客\",\"websiteRecordNo\":\"备案号\",\"websocketUrl\":\"ws://127.0.0.1:8080/websocket\",\"weiXinQRCode\":\"1613170123965743105\"}', '2021-08-09 19:37:30', NULL); + +-- ---------------------------- +-- Table structure for gen_table +-- ---------------------------- +DROP TABLE IF EXISTS `gen_table`; +CREATE TABLE `gen_table` ( + `table_id` bigint(20) NOT NULL COMMENT '编号', + `table_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '表名称', + `table_comment` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '表描述', + `sub_table_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '关联子表的表名', + `sub_table_fk_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '子表关联的外键名', + `class_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '实体类名称', + `tpl_category` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'crud' COMMENT '使用的模板(crud单表操作 tree树表操作)', + `package_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成包路径', + `module_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成模块名', + `business_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成业务名', + `function_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成功能名', + `function_author` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '生成功能作者', + `gen_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '生成代码方式(0zip压缩包 1自定义路径)', + `gen_path` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '/' COMMENT '生成路径(不填默认项目路径)', + `options` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '其它生成选项', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`table_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '代码生成业务表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_table +-- ---------------------------- +INSERT INTO `gen_table` VALUES (1611335897880530945, 'blog_article', '文章列表', NULL, NULL, 'Article', 'crud', 'com.zhi.blog', 'article', 'article', '文章列表', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"}', 'admin', '2023-01-06 20:15:34', 'admin', '2023-01-07 12:45:11', NULL); +INSERT INTO `gen_table` VALUES (1611611446079225858, 'blog_category', '分类管理', NULL, NULL, 'Category', 'crud', 'com.zhi.blog', 'category', 'category', '分类管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"}', 'admin', '2023-01-07 14:30:58', 'admin', '2023-01-07 14:40:26', '分类管理'); +INSERT INTO `gen_table` VALUES (1611975642985832449, 'blog_tag', '标签管理', NULL, NULL, 'Tag', 'crud', 'com.zhi.blog', 'tag', 'tag', '标签管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"}', 'admin', '2023-01-08 14:38:04', 'admin', '2023-01-08 14:59:50', '标签管理'); +INSERT INTO `gen_table` VALUES (1612801946723414017, 'blog_comment', '评论管理', NULL, NULL, 'Comment', 'crud', 'com.zhi.blog', 'comment', 'comment', '评论管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"}', 'admin', '2023-01-10 21:01:07', 'admin', '2023-01-10 22:27:01', '评论管理'); +INSERT INTO `gen_table` VALUES (1613097812961054721, 'blog_message', '留言管理', NULL, NULL, 'Message', 'crud', 'com.zhi.blog', 'message', 'message', '留言管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"}', 'admin', '2023-01-11 16:56:31', 'admin', '2023-01-11 16:59:44', '留言管理'); +INSERT INTO `gen_table` VALUES (1613391695125204993, 'blog_page', '页面管理', NULL, NULL, 'BlogPage', 'crud', 'com.zhi.blog', 'page', 'page', '页面管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"}', 'admin', '2023-01-11 21:53:14', 'admin', '2023-01-12 12:50:07', '页面管理'); +INSERT INTO `gen_table` VALUES (1613408128559218689, 'blog_friend_link', '友链管理', NULL, NULL, 'FriendLink', 'crud', 'com.zhi.blog', 'friendLink', 'friendLink', '友链管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"}', 'admin', '2023-01-12 13:23:28', 'admin', '2023-01-12 13:33:11', '友链管理'); +INSERT INTO `gen_table` VALUES (1613814814495215617, 'blog_talk', '说说管理', NULL, NULL, 'Talk', 'crud', 'com.zhi.blog', 'talk', 'talk', '说说管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613813815185510401\"}', 'admin', '2023-01-13 16:14:15', 'admin', '2023-01-13 16:42:08', '说说管理'); +INSERT INTO `gen_table` VALUES (1627638276586246146, 'blog_photo_album', '相册管理', NULL, NULL, 'Album', 'crud', 'com.zhi.blog', 'album', 'album', '相册管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1627642998340730881\"}', 'admin', '2023-02-20 19:55:16', 'admin', '2023-02-20 20:15:28', '相册管理'); +INSERT INTO `gen_table` VALUES (1627992801939582977, 'blog_photo', '照片管理', NULL, NULL, 'Photo', 'crud', 'com.zhi.blog', 'photo', 'photo', '照片管理', 'ftz', '0', '/', '{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1627642998340730881\"}', 'admin', '2023-02-20 19:54:42', 'admin', '2023-02-21 19:46:30', '照片管理'); + +-- ---------------------------- +-- Table structure for gen_table_column +-- ---------------------------- +DROP TABLE IF EXISTS `gen_table_column`; +CREATE TABLE `gen_table_column` ( + `column_id` bigint(20) NOT NULL COMMENT '编号', + `table_id` bigint(20) NULL DEFAULT NULL COMMENT '归属表编号', + `column_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '列名称', + `column_comment` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '列描述', + `column_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '列类型', + `java_type` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'JAVA类型', + `java_field` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'JAVA字段名', + `is_pk` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否主键(1是)', + `is_increment` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否自增(1是)', + `is_required` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否必填(1是)', + `is_insert` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否为插入字段(1是)', + `is_edit` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否编辑字段(1是)', + `is_list` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否列表字段(1是)', + `is_query` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '是否查询字段(1是)', + `query_type` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)', + `html_type` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)', + `dict_type` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典类型', + `sort` int(11) NULL DEFAULT NULL COMMENT '排序', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`column_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '代码生成业务表字段' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of gen_table_column +-- ---------------------------- +INSERT INTO `gen_table_column` VALUES (1611335898031525890, 1611335897880530945, 'id', '', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898031525891, 1611335897880530945, 'user_id', '作者', 'int(11)', 'Long', 'userId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 2, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274626, 1611335897880530945, 'category_id', '文章分类', 'int(11)', 'Long', 'categoryId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 3, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274627, 1611335897880530945, 'article_cover', '文章缩略图', 'varchar(1024)', 'String', 'articleCover', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'imageUpload', '', 4, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274628, 1611335897880530945, 'article_title', '标题', 'varchar(50)', 'String', 'articleTitle', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 5, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274629, 1611335897880530945, 'article_content', '内容', 'longtext', 'String', 'articleContent', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'editor', '', 6, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274630, 1611335897880530945, 'type', '文章类型 1原创 2转载 3翻译', 'tinyint(1)', 'Integer', 'type', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', 'article_type', 7, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274631, 1611335897880530945, 'original_url', '原文链接', 'varchar(255)', 'String', 'originalUrl', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 8, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274632, 1611335897880530945, 'is_top', '是否置顶 0否 1是', 'tinyint(1)', 'Integer', 'isTop', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', 'sys_yes_no', 9, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274633, 1611335897880530945, 'is_delete', '是否删除 0否 1是', 'tinyint(1)', 'Integer', 'isDelete', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', 'sys_yes_no', 10, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274634, 1611335897880530945, 'status', '状态值 1公开 2私密 3评论可见', 'tinyint(1)', 'Integer', 'status', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', 'article_status', 11, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274635, 1611335897880530945, 'create_time', '发表时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 12, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274636, 1611335897880530945, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 13, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274637, 1611335897880530945, 'like_count', '点赞数', 'int(11)', 'Long', 'likeCount', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 14, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274638, 1611335897880530945, 'views_count', '浏览量', 'int(11)', 'Long', 'viewsCount', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 15, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274639, 1611335897880530945, 'create_by', '', 'varchar(255)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 16, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611335898069274640, 1611335897880530945, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 17, 'admin', '2023-01-06 20:16:30', 'admin', '2023-01-07 12:45:11'); +INSERT INTO `gen_table_column` VALUES (1611611446146334721, 1611611446079225858, 'id', '', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-07 14:31:26', 'admin', '2023-01-07 14:40:26'); +INSERT INTO `gen_table_column` VALUES (1611611446146334722, 1611611446079225858, 'category_name', '分类名', 'varchar(20)', 'String', 'categoryName', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 2, 'admin', '2023-01-07 14:31:26', 'admin', '2023-01-07 14:40:26'); +INSERT INTO `gen_table_column` VALUES (1611611446146334723, 1611611446079225858, 'create_time', '创建时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 3, 'admin', '2023-01-07 14:31:26', 'admin', '2023-01-07 14:40:26'); +INSERT INTO `gen_table_column` VALUES (1611611446146334724, 1611611446079225858, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 4, 'admin', '2023-01-07 14:31:26', 'admin', '2023-01-07 14:40:26'); +INSERT INTO `gen_table_column` VALUES (1611611446146334725, 1611611446079225858, 'create_by', '创建人', 'varchar(20)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 5, 'admin', '2023-01-07 14:31:26', 'admin', '2023-01-07 14:40:26'); +INSERT INTO `gen_table_column` VALUES (1611611446146334726, 1611611446079225858, 'update_by', '更新用户', 'varchar(20)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 6, 'admin', '2023-01-07 14:31:26', 'admin', '2023-01-07 14:40:26'); +INSERT INTO `gen_table_column` VALUES (1611975643027775489, 1611975642985832449, 'id', '', 'int(11)', 'Long', 'id', '1', '0', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-08 14:38:37', 'admin', '2023-01-08 14:59:50'); +INSERT INTO `gen_table_column` VALUES (1611975643027775490, 1611975642985832449, 'tag_name', '标签名', 'varchar(11)', 'String', 'tagName', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 2, 'admin', '2023-01-08 14:38:37', 'admin', '2023-01-08 14:59:50'); +INSERT INTO `gen_table_column` VALUES (1611975643078107137, 1611975642985832449, 'create_by', '', 'varchar(20)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 3, 'admin', '2023-01-08 14:38:37', 'admin', '2023-01-08 14:59:50'); +INSERT INTO `gen_table_column` VALUES (1611975643078107138, 1611975642985832449, 'create_time', '', 'datetime', 'Date', 'createTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 4, 'admin', '2023-01-08 14:38:37', 'admin', '2023-01-08 14:59:50'); +INSERT INTO `gen_table_column` VALUES (1611975643078107139, 1611975642985832449, 'update_by', '', 'varchar(20)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 5, 'admin', '2023-01-08 14:38:37', 'admin', '2023-01-08 14:59:50'); +INSERT INTO `gen_table_column` VALUES (1611975643078107140, 1611975642985832449, 'update_time', '', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 6, 'admin', '2023-01-08 14:38:37', 'admin', '2023-01-08 14:59:50'); +INSERT INTO `gen_table_column` VALUES (1612801946790522881, 1612801946723414017, 'id', '主键', 'bigint(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946790522882, 1612801946723414017, 'user_id', '评论用户Id', 'bigint(11)', 'Long', 'userId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 2, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946790522883, 1612801946723414017, 'comment_content', '评论内容', 'text', 'String', 'commentContent', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'textarea', '', 3, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946790522884, 1612801946723414017, 'reply_user_id', '回复用户id', 'int(11)', 'Long', 'replyUserId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 4, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946790522885, 1612801946723414017, 'parent_id', '父评论id', 'int(11)', 'Long', 'parentId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 5, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631746, 1612801946723414017, 'type', '评论类型 1.文章 2.友链 3.说说', 'tinyint(4)', 'Integer', 'type', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'select', 'commen_type', 6, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631747, 1612801946723414017, 'is_delete', '是否删除 0否 1是', 'tinyint(4)', 'Integer', 'isDelete', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 7, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631749, 1612801946723414017, 'create_time', '评论时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 8, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631750, 1612801946723414017, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 9, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631751, 1612801946723414017, 'topic_id', '评论主题id', 'int(11)', 'Long', 'topicId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 10, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631752, 1612801946723414017, 'ip_address', '评论ip', 'varchar(50)', 'String', 'ipAddress', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 11, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612801946857631753, 1612801946723414017, 'ip_source', '真实地址', 'varchar(50)', 'String', 'ipSource', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 12, 'admin', '2023-01-10 21:22:03', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612809899010551810, 1612801946723414017, 'state', '评论状态', 'int(10)', 'Integer', 'state', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'select', 'comment_status', 13, 'admin', '2023-01-10 21:53:39', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612811822023344130, 1612801946723414017, 'create_by', '创建人', 'varchar(20)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 14, 'admin', '2023-01-10 22:01:18', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1612812816513810434, 1612801946723414017, 'update_by', '更新人', 'varchar(20)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 15, 'admin', '2023-01-10 22:05:15', 'admin', '2023-01-10 22:27:01'); +INSERT INTO `gen_table_column` VALUES (1613097813036552193, 1613097812961054721, 'id', '主键id', 'bigint(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813036552194, 1613097812961054721, 'nickname', '昵称', 'varchar(50)', 'String', 'nickname', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 2, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813036552195, 1613097812961054721, 'avatar', '头像', 'varchar(255)', 'String', 'avatar', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'imageUpload', '', 3, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078145, 1613097812961054721, 'message_content', '留言内容', 'varchar(255)', 'String', 'messageContent', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'textarea', '', 4, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078146, 1613097812961054721, 'ip_address', '用户ip', 'varchar(50)', 'String', 'ipAddress', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'input', '', 5, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078147, 1613097812961054721, 'ip_source', '用户地址', 'varchar(255)', 'String', 'ipSource', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'input', '', 6, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078148, 1613097812961054721, 'time', '弹幕速度', 'tinyint(1)', 'Integer', 'time', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 7, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078149, 1613097812961054721, 'is_review', '是否审核', 'varchar(4)', 'String', 'isReview', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', 'sys_yes_no', 8, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078150, 1613097812961054721, 'create_time', '发布时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 9, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078151, 1613097812961054721, 'update_time', '修改时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 10, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078152, 1613097812961054721, 'create_by', '', 'varchar(10)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 11, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613097813091078153, 1613097812961054721, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 12, 'admin', '2023-01-11 16:57:43', 'admin', '2023-01-11 16:59:44'); +INSERT INTO `gen_table_column` VALUES (1613391695188119553, 1613391695125204993, 'id', '页面id', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-12 12:25:30', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613391695188119554, 1613391695125204993, 'page_name', '页面名', 'varchar(10)', 'String', 'pageName', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 2, 'admin', '2023-01-12 12:25:30', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613391695255228418, 1613391695125204993, 'page_label', '页面标签', 'varchar(20)', 'String', 'pageLabel', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 3, 'admin', '2023-01-12 12:25:30', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613391695255228419, 1613391695125204993, 'page_cover', '页面封面', 'varchar(255)', 'String', 'pageCover', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'imageUpload', '', 4, 'admin', '2023-01-12 12:25:30', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613391695255228420, 1613391695125204993, 'create_time', '创建时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 5, 'admin', '2023-01-12 12:25:30', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613391695255228421, 1613391695125204993, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 6, 'admin', '2023-01-12 12:25:30', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613395321428168705, 1613391695125204993, 'create_by', '', 'varchar(10)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 7, 'admin', '2023-01-12 12:39:55', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613395321428168706, 1613391695125204993, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 8, 'admin', '2023-01-12 12:39:55', 'admin', '2023-01-12 12:50:07'); +INSERT INTO `gen_table_column` VALUES (1613408128626327554, 1613408128559218689, 'id', '', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128626327555, 1613408128559218689, 'link_name', '链接名', 'varchar(20)', 'String', 'linkName', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 2, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128626327556, 1613408128559218689, 'link_avatar', '链接头像', 'varchar(255)', 'String', 'linkAvatar', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'imageUpload', '', 3, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128626327557, 1613408128559218689, 'link_address', '链接地址', 'varchar(50)', 'String', 'linkAddress', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 4, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128693436418, 1613408128559218689, 'link_intro', '链接介绍', 'varchar(100)', 'String', 'linkIntro', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 5, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128693436419, 1613408128559218689, 'create_time', '创建时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 6, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128693436420, 1613408128559218689, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 7, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128693436421, 1613408128559218689, 'create_by', '', 'varchar(10)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 8, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613408128693436422, 1613408128559218689, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 9, 'admin', '2023-01-12 13:30:48', 'admin', '2023-01-12 13:33:11'); +INSERT INTO `gen_table_column` VALUES (1613814814495215618, 1613814814495215617, 'id', '说说id', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814495215619, 1613814814495215617, 'user_id', '用户id', 'int(11)', 'Long', 'userId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 2, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814495215620, 1613814814495215617, 'content', '说说内容', 'varchar(2000)', 'String', 'content', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'editor', '', 3, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814495215621, 1613814814495215617, 'images', '图片', 'varchar(2500)', 'String', 'images', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'imageUpload', '', 4, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814495215622, 1613814814495215617, 'is_top', '是否置顶', 'tinyint(1)', 'Integer', 'isTop', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'radio', 'sys_yes_no', 5, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814562324482, 1613814814495215617, 'create_time', '创建时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 6, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814562324483, 1613814814495215617, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 7, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814562324484, 1613814814495215617, 'create_by', '', 'varchar(10)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 8, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1613814814562324485, 1613814814495215617, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 9, 'admin', '2023-01-13 16:26:50', 'admin', '2023-01-13 16:42:08'); +INSERT INTO `gen_table_column` VALUES (1627638276653355010, 1627638276586246146, 'id', '主键', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276653355011, 1627638276586246146, 'album_name', '相册名', 'varchar(20)', 'String', 'albumName', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 2, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276653355012, 1627638276586246146, 'album_desc', '相册描述', 'varchar(50)', 'String', 'albumDesc', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 3, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276653355013, 1627638276586246146, 'album_cover', '相册封面', 'varchar(255)', 'String', 'albumCover', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'imageUpload', '', 4, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276653355014, 1627638276586246146, 'is_delete', '是否删除', 'tinyint(1)', 'Integer', 'isDelete', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', 'sys_yes_no', 5, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276653355015, 1627638276586246146, 'status', '状态值 1公开 2私密', 'tinyint(1)', 'Integer', 'status', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'radio', '', 6, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276653355016, 1627638276586246146, 'create_time', '创建时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 7, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276712075265, 1627638276586246146, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 8, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276712075266, 1627638276586246146, 'create_by', '', 'varchar(10)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 9, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627638276712075267, 1627638276586246146, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 10, 'admin', '2023-02-20 19:56:20', 'admin', '2023-02-20 20:15:28'); +INSERT INTO `gen_table_column` VALUES (1627992802002497537, 1627992801939582977, 'id', '主键', 'int(11)', 'Long', 'id', '1', '1', '1', NULL, '1', '1', NULL, 'EQ', 'input', '', 1, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497538, 1627992801939582977, 'album_id', '相册id', 'int(11)', 'Long', 'albumId', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 2, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497539, 1627992801939582977, 'photo_name', '照片名', 'varchar(20)', 'String', 'photoName', '0', '0', '1', '1', '1', '1', '1', 'LIKE', 'input', '', 3, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497540, 1627992801939582977, 'photo_desc', '照片描述', 'varchar(50)', 'String', 'photoDesc', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 4, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497541, 1627992801939582977, 'photo_src', '照片地址', 'varchar(255)', 'String', 'photoSrc', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 5, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497542, 1627992801939582977, 'is_delete', '是否删除', 'tinyint(1)', 'Integer', 'isDelete', '0', '0', '1', '1', '1', '1', '1', 'EQ', 'input', '', 6, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497543, 1627992801939582977, 'create_time', '创建时间', 'datetime', 'Date', 'createTime', '0', '0', '1', NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 7, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802002497544, 1627992801939582977, 'update_time', '更新时间', 'datetime', 'Date', 'updateTime', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'datetime', '', 8, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802065412097, 1627992801939582977, 'create_by', '', 'varchar(10)', 'String', 'createBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 9, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); +INSERT INTO `gen_table_column` VALUES (1627992802065412098, 1627992801939582977, 'update_by', '', 'varchar(10)', 'String', 'updateBy', '0', '0', NULL, NULL, NULL, NULL, NULL, 'EQ', 'input', '', 10, 'admin', '2023-02-21 19:25:05', 'admin', '2023-02-21 19:46:30'); + +-- ---------------------------- +-- Table structure for sys_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_config`; +CREATE TABLE `sys_config` ( + `config_id` bigint(20) NOT NULL COMMENT '参数主键', + `config_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '参数名称', + `config_key` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '参数键名', + `config_value` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '参数键值', + `config_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'N' COMMENT '系统内置(Y是 N否)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`config_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '参数配置表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_config +-- ---------------------------- +INSERT INTO `sys_config` VALUES (1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2023-01-05 19:54:19', '', NULL, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +INSERT INTO `sys_config` VALUES (2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2023-01-05 19:54:19', '', NULL, '初始化密码 123456'); +INSERT INTO `sys_config` VALUES (3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2023-01-05 19:54:19', '', NULL, '深色主题theme-dark,浅色主题theme-light'); +INSERT INTO `sys_config` VALUES (4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', '2023-01-05 19:54:19', '', NULL, '是否开启验证码功能(true开启,false关闭)'); +INSERT INTO `sys_config` VALUES (5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', '2023-01-05 19:54:19', '', NULL, '是否开启注册用户功能(true开启,false关闭)'); +INSERT INTO `sys_config` VALUES (11, 'OSS预览列表资源开关', 'sys.oss.previewListResource', 'true', 'Y', 'admin', '2023-01-05 19:54:19', '', NULL, 'true:开启, false:关闭'); + +-- ---------------------------- +-- Table structure for sys_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dept`; +CREATE TABLE `sys_dept` ( + `dept_id` bigint(20) NOT NULL COMMENT '部门id', + `parent_id` bigint(20) NULL DEFAULT 0 COMMENT '父部门id', + `ancestors` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '祖级列表', + `dept_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '部门名称', + `order_num` int(4) NULL DEFAULT 0 COMMENT '显示顺序', + `leader` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '负责人', + `phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '部门状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`dept_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '部门表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dept +-- ---------------------------- +INSERT INTO `sys_dept` VALUES (100, 0, '0', 'water-之', 0, 'ftz', '15888888888', 'ftz@qq.com', '0', '0', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-15 14:24:42'); +INSERT INTO `sys_dept` VALUES (101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2023-01-05 19:54:19', '', NULL); +INSERT INTO `sys_dept` VALUES (103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '2', 'admin', '2023-01-05 19:54:19', '', NULL); +INSERT INTO `sys_dept` VALUES (104, 100, '0,100', '芝士团', 1, 'ftz', '18888888888', '2831826106@qq.com', '0', '0', 'admin', '2023-01-15 14:25:36', 'admin', '2023-01-15 14:25:36'); + +-- ---------------------------- +-- Table structure for sys_dict_data +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_data`; +CREATE TABLE `sys_dict_data` ( + `dict_code` bigint(20) NOT NULL COMMENT '字典编码', + `dict_sort` int(4) NULL DEFAULT 0 COMMENT '字典排序', + `dict_label` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典标签', + `dict_value` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典键值', + `dict_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典类型', + `css_class` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '样式属性(其他样式扩展)', + `list_class` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '表格回显样式', + `is_default` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'N' COMMENT '是否默认(Y是 N否)', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dict_code`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '字典数据表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_data +-- ---------------------------- +INSERT INTO `sys_dict_data` VALUES (1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '性别男'); +INSERT INTO `sys_dict_data` VALUES (2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '性别女'); +INSERT INTO `sys_dict_data` VALUES (3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '性别未知'); +INSERT INTO `sys_dict_data` VALUES (4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '显示菜单'); +INSERT INTO `sys_dict_data` VALUES (5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '隐藏菜单'); +INSERT INTO `sys_dict_data` VALUES (6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '系统默认是'); +INSERT INTO `sys_dict_data` VALUES (13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '系统默认否'); +INSERT INTO `sys_dict_data` VALUES (14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '通知'); +INSERT INTO `sys_dict_data` VALUES (15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '公告'); +INSERT INTO `sys_dict_data` VALUES (16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '关闭状态'); +INSERT INTO `sys_dict_data` VALUES (18, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '新增操作'); +INSERT INTO `sys_dict_data` VALUES (19, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '修改操作'); +INSERT INTO `sys_dict_data` VALUES (20, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '删除操作'); +INSERT INTO `sys_dict_data` VALUES (21, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '授权操作'); +INSERT INTO `sys_dict_data` VALUES (22, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '导出操作'); +INSERT INTO `sys_dict_data` VALUES (23, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '导入操作'); +INSERT INTO `sys_dict_data` VALUES (24, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '强退操作'); +INSERT INTO `sys_dict_data` VALUES (25, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '生成操作'); +INSERT INTO `sys_dict_data` VALUES (26, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '清空操作'); +INSERT INTO `sys_dict_data` VALUES (27, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '正常状态'); +INSERT INTO `sys_dict_data` VALUES (28, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '停用状态'); +INSERT INTO `sys_dict_data` VALUES (29, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '其他操作'); +INSERT INTO `sys_dict_data` VALUES (30, 1, '原创', '1', 'article_type', NULL, 'success', 'N', '0', 'admin', '2023-01-06 19:52:34', 'admin', '2023-01-06 20:41:07', '原创'); +INSERT INTO `sys_dict_data` VALUES (31, 2, '转载', '2', 'article_type', NULL, 'danger', 'N', '0', 'admin', '2023-01-06 19:52:56', 'admin', '2023-01-06 20:41:29', NULL); +INSERT INTO `sys_dict_data` VALUES (32, 3, '翻译', '3', 'article_type', NULL, 'warning', 'N', '0', 'admin', '2023-01-06 19:53:06', 'admin', '2023-01-06 20:41:23', NULL); +INSERT INTO `sys_dict_data` VALUES (33, 0, '公开', '1', 'article_status', NULL, 'success', 'N', '0', 'admin', '2023-01-06 20:38:58', 'admin', '2023-01-07 12:48:05', NULL); +INSERT INTO `sys_dict_data` VALUES (34, 0, '私密', '2', 'article_status', NULL, 'warning', 'N', '0', 'admin', '2023-01-06 20:39:07', 'admin', '2023-01-07 12:48:14', NULL); +INSERT INTO `sys_dict_data` VALUES (35, 0, '评论可见', '3', 'article_status', NULL, 'primary', 'N', '0', 'admin', '2023-01-06 20:39:20', 'admin', '2023-01-07 12:48:20', NULL); +INSERT INTO `sys_dict_data` VALUES (36, 0, '文章', '1', 'commen_type', NULL, 'primary', 'N', '0', 'admin', '2023-01-10 21:27:14', 'admin', '2023-01-10 21:27:14', '文章'); +INSERT INTO `sys_dict_data` VALUES (37, 0, '友链', '2', 'commen_type', NULL, 'success', 'N', '0', 'admin', '2023-01-10 21:27:39', 'admin', '2023-01-10 21:28:18', '友链'); +INSERT INTO `sys_dict_data` VALUES (38, 0, '说说', '3', 'commen_type', NULL, 'warning', 'N', '0', 'admin', '2023-01-10 21:28:07', 'admin', '2023-01-10 21:28:07', '说说'); +INSERT INTO `sys_dict_data` VALUES (39, 0, '审核通过', '1', 'comment_status', NULL, 'success', 'N', '0', 'admin', '2023-01-10 21:51:23', 'admin', '2023-01-10 21:51:23', '审核通过'); +INSERT INTO `sys_dict_data` VALUES (40, 0, '审核中', '2', 'comment_status', NULL, 'primary', 'N', '0', 'admin', '2023-01-10 21:51:51', 'admin', '2023-01-10 21:51:51', '审核中'); +INSERT INTO `sys_dict_data` VALUES (41, 0, '未通过审核', '3', 'comment_status', NULL, 'danger', 'N', '0', 'admin', '2023-01-10 21:52:12', 'admin', '2023-01-10 21:52:12', '审核不通过'); + +-- ---------------------------- +-- Table structure for sys_dict_type +-- ---------------------------- +DROP TABLE IF EXISTS `sys_dict_type`; +CREATE TABLE `sys_dict_type` ( + `dict_id` bigint(20) NOT NULL COMMENT '字典主键', + `dict_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典名称', + `dict_type` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '字典类型', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`dict_id`) USING BTREE, + UNIQUE INDEX `dict_type`(`dict_type` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '字典类型表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_dict_type +-- ---------------------------- +INSERT INTO `sys_dict_type` VALUES (1, '用户性别', 'sys_user_sex', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '用户性别列表'); +INSERT INTO `sys_dict_type` VALUES (2, '菜单状态', 'sys_show_hide', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '菜单状态列表'); +INSERT INTO `sys_dict_type` VALUES (3, '系统开关', 'sys_normal_disable', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '系统开关列表'); +INSERT INTO `sys_dict_type` VALUES (6, '系统是否', 'sys_yes_no', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '系统是否列表'); +INSERT INTO `sys_dict_type` VALUES (7, '通知类型', 'sys_notice_type', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '通知类型列表'); +INSERT INTO `sys_dict_type` VALUES (8, '通知状态', 'sys_notice_status', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '通知状态列表'); +INSERT INTO `sys_dict_type` VALUES (9, '操作类型', 'sys_oper_type', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '操作类型列表'); +INSERT INTO `sys_dict_type` VALUES (10, '系统状态', 'sys_common_status', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '登录状态列表'); +INSERT INTO `sys_dict_type` VALUES (11, '文章类型', 'article_type', '0', 'admin', '2023-01-06 19:51:08', 'admin', '2023-01-06 19:51:08', '文章类型'); +INSERT INTO `sys_dict_type` VALUES (12, '文章状态', 'article_status', '0', 'admin', '2023-01-06 20:37:58', 'admin', '2023-01-06 20:37:58', '文章状态'); +INSERT INTO `sys_dict_type` VALUES (13, '评论类型', 'commen_type', '0', 'admin', '2023-01-10 21:26:09', 'admin', '2023-01-10 21:49:47', '评论类型'); +INSERT INTO `sys_dict_type` VALUES (14, '评论状态', 'comment_status', '0', 'admin', '2023-01-10 21:49:32', 'admin', '2023-01-10 21:50:32', '评论状态'); + +-- ---------------------------- +-- Table structure for sys_logininfor +-- ---------------------------- +DROP TABLE IF EXISTS `sys_logininfor`; +CREATE TABLE `sys_logininfor` ( + `info_id` bigint(20) NOT NULL COMMENT '访问ID', + `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户账号', + `ipaddr` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '登录IP地址', + `login_location` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '登录地点', + `browser` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '浏览器类型', + `os` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作系统', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '登录状态(0成功 1失败)', + `msg` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '提示消息', + `login_time` datetime NULL DEFAULT NULL COMMENT '访问时间', + PRIMARY KEY (`info_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '系统访问记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_logininfor +-- ---------------------------- +INSERT INTO `sys_logininfor` VALUES (1611299423906770946, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-06 17:51:34'); +INSERT INTO `sys_logininfor` VALUES (1611317393630523393, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-06 19:02:58'); +INSERT INTO `sys_logininfor` VALUES (1611328359785132033, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-06 19:46:33'); +INSERT INTO `sys_logininfor` VALUES (1611339128903925761, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-06 20:29:20'); +INSERT INTO `sys_logininfor` VALUES (1611574895685263361, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 12:06:11'); +INSERT INTO `sys_logininfor` VALUES (1611579610619805697, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-01-07 12:24:56'); +INSERT INTO `sys_logininfor` VALUES (1611579626721738753, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 12:24:59'); +INSERT INTO `sys_logininfor` VALUES (1611601032943599618, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 13:50:03'); +INSERT INTO `sys_logininfor` VALUES (1611619601005674498, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 15:03:50'); +INSERT INTO `sys_logininfor` VALUES (1611623469097680898, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-07 15:19:12'); +INSERT INTO `sys_logininfor` VALUES (1611623483651915777, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 15:19:16'); +INSERT INTO `sys_logininfor` VALUES (1611636338011000834, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 16:10:20'); +INSERT INTO `sys_logininfor` VALUES (1611728373501931521, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-07 22:16:03'); +INSERT INTO `sys_logininfor` VALUES (1611933231484059649, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-08 11:50:05'); +INSERT INTO `sys_logininfor` VALUES (1611951754201546753, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-08 13:03:41'); +INSERT INTO `sys_logininfor` VALUES (1612006137933094914, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-08 16:39:48'); +INSERT INTO `sys_logininfor` VALUES (1612095882617004033, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-08 22:36:24'); +INSERT INTO `sys_logininfor` VALUES (1612283570628403201, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-09 11:02:13'); +INSERT INTO `sys_logininfor` VALUES (1612362677043085313, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-09 16:16:33'); +INSERT INTO `sys_logininfor` VALUES (1612415216702783490, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-09 19:45:20'); +INSERT INTO `sys_logininfor` VALUES (1612430246575947777, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-09 20:45:03'); +INSERT INTO `sys_logininfor` VALUES (1612462839132344321, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-09 22:54:34'); +INSERT INTO `sys_logininfor` VALUES (1612672676365664257, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-10 12:48:23'); +INSERT INTO `sys_logininfor` VALUES (1612685743216459778, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-10 13:40:18'); +INSERT INTO `sys_logininfor` VALUES (1612780928030076929, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-10 19:58:32'); +INSERT INTO `sys_logininfor` VALUES (1612796731911696385, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-10 21:01:20'); +INSERT INTO `sys_logininfor` VALUES (1613014077653680130, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-11 11:24:59'); +INSERT INTO `sys_logininfor` VALUES (1613030283009884161, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-01-11 12:29:23'); +INSERT INTO `sys_logininfor` VALUES (1613030297329238018, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-11 12:29:26'); +INSERT INTO `sys_logininfor` VALUES (1613095742270918657, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-01-11 16:49:29'); +INSERT INTO `sys_logininfor` VALUES (1613095755755606018, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-11 16:49:33'); +INSERT INTO `sys_logininfor` VALUES (1613133193999892481, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-11 19:18:19'); +INSERT INTO `sys_logininfor` VALUES (1613147414158434305, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-11 20:14:49'); +INSERT INTO `sys_logininfor` VALUES (1613156243768139778, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-11 20:49:54'); +INSERT INTO `sys_logininfor` VALUES (1613391154018045953, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-01-12 12:23:21'); +INSERT INTO `sys_logininfor` VALUES (1613391166097641474, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-12 12:23:24'); +INSERT INTO `sys_logininfor` VALUES (1613399225163399170, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-12 12:55:25'); +INSERT INTO `sys_logininfor` VALUES (1613462999048196097, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-12 17:08:50'); +INSERT INTO `sys_logininfor` VALUES (1613795829213093890, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 15:11:23'); +INSERT INTO `sys_logininfor` VALUES (1613804936070488066, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 15:47:34'); +INSERT INTO `sys_logininfor` VALUES (1613813479037210626, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 16:21:31'); +INSERT INTO `sys_logininfor` VALUES (1613818016481468418, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 16:39:33'); +INSERT INTO `sys_logininfor` VALUES (1613860597596745730, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 19:28:45'); +INSERT INTO `sys_logininfor` VALUES (1613864271295344641, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 19:43:21'); +INSERT INTO `sys_logininfor` VALUES (1613864477042733058, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 19:44:10'); +INSERT INTO `sys_logininfor` VALUES (1613875842738311169, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-13 20:29:20'); +INSERT INTO `sys_logininfor` VALUES (1614110239337017345, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-14 12:00:44'); +INSERT INTO `sys_logininfor` VALUES (1614201878906683394, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-14 18:04:53'); +INSERT INTO `sys_logininfor` VALUES (1614223041905147905, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-14 19:28:59'); +INSERT INTO `sys_logininfor` VALUES (1614224418916122625, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-14 19:34:27'); +INSERT INTO `sys_logininfor` VALUES (1614224504811274241, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-14 19:34:47'); +INSERT INTO `sys_logininfor` VALUES (1614250835003334657, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-14 21:19:25'); +INSERT INTO `sys_logininfor` VALUES (1614269344081006593, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-14 22:32:58'); +INSERT INTO `sys_logininfor` VALUES (1614476058919243778, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 12:14:23'); +INSERT INTO `sys_logininfor` VALUES (1614508501265047553, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 14:23:17'); +INSERT INTO `sys_logininfor` VALUES (1614548379788914689, '老妈', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-15 17:01:45'); +INSERT INTO `sys_logininfor` VALUES (1614548939325845506, '老爸', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-15 17:03:59'); +INSERT INTO `sys_logininfor` VALUES (1614549974173888513, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 17:08:05'); +INSERT INTO `sys_logininfor` VALUES (1614563330284957697, '老爸', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 18:01:10'); +INSERT INTO `sys_logininfor` VALUES (1614568261498822658, '老爸', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 18:20:45'); +INSERT INTO `sys_logininfor` VALUES (1614570378099720194, '老爸', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 18:29:10'); +INSERT INTO `sys_logininfor` VALUES (1614571208295088130, '老爸', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 18:32:28'); +INSERT INTO `sys_logininfor` VALUES (1614580558325612546, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 19:09:37'); +INSERT INTO `sys_logininfor` VALUES (1614589224999297025, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 19:44:04'); +INSERT INTO `sys_logininfor` VALUES (1614592580480245761, '老爸', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 19:57:24'); +INSERT INTO `sys_logininfor` VALUES (1614592876329672706, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 19:58:34'); +INSERT INTO `sys_logininfor` VALUES (1614624165925490689, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-15 22:02:54'); +INSERT INTO `sys_logininfor` VALUES (1614869344561524738, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-16 14:17:09'); +INSERT INTO `sys_logininfor` VALUES (1614884718728212482, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-16 15:18:15'); +INSERT INTO `sys_logininfor` VALUES (1614985346641092610, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-16 21:58:06'); +INSERT INTO `sys_logininfor` VALUES (1614986721873682434, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码已失效', '2023-01-16 22:03:34'); +INSERT INTO `sys_logininfor` VALUES (1614986738340519938, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-16 22:03:38'); +INSERT INTO `sys_logininfor` VALUES (1614991232491118594, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-16 22:21:30'); +INSERT INTO `sys_logininfor` VALUES (1615200333963812866, '月色', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 12:12:23'); +INSERT INTO `sys_logininfor` VALUES (1615200756154064898, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 12:14:04'); +INSERT INTO `sys_logininfor` VALUES (1615202532001406978, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-17 12:21:07'); +INSERT INTO `sys_logininfor` VALUES (1615202599118659585, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 12:21:23'); +INSERT INTO `sys_logininfor` VALUES (1615222513904668673, '测试', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-17 13:40:31'); +INSERT INTO `sys_logininfor` VALUES (1615222514512842754, '测试', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 13:40:32'); +INSERT INTO `sys_logininfor` VALUES (1615223161412931586, '最后的测试', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-17 13:43:06'); +INSERT INTO `sys_logininfor` VALUES (1615223162398593026, '最后的测试', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 13:43:06'); +INSERT INTO `sys_logininfor` VALUES (1615224211964448769, 'lasttest', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-17 13:47:16'); +INSERT INTO `sys_logininfor` VALUES (1615224213013024770, 'lasttest', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 13:47:16'); +INSERT INTO `sys_logininfor` VALUES (1615233660485709826, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 14:24:49'); +INSERT INTO `sys_logininfor` VALUES (1615238968490668033, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码已失效', '2023-01-17 14:45:54'); +INSERT INTO `sys_logininfor` VALUES (1615238979475550209, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 14:45:57'); +INSERT INTO `sys_logininfor` VALUES (1615253597279301634, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 15:44:02'); +INSERT INTO `sys_logininfor` VALUES (1615316735194411009, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-17 19:54:55'); +INSERT INTO `sys_logininfor` VALUES (1615639724200947713, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-18 17:18:22'); +INSERT INTO `sys_logininfor` VALUES (1615662360482045953, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-18 18:48:19'); +INSERT INTO `sys_logininfor` VALUES (1616078016146841602, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 22:19:59'); +INSERT INTO `sys_logininfor` VALUES (1616078308485636098, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 22:21:09'); +INSERT INTO `sys_logininfor` VALUES (1616078751743877121, 'lionli', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '密码输入错误1次', '2023-01-19 22:22:54'); +INSERT INTO `sys_logininfor` VALUES (1616078823239983106, '月色', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 22:23:11'); +INSERT INTO `sys_logininfor` VALUES (1616083640775622658, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 22:42:20'); +INSERT INTO `sys_logininfor` VALUES (1616084083316637697, '荷塘', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 22:44:06'); +INSERT INTO `sys_logininfor` VALUES (1616086965671706625, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 22:55:33'); +INSERT INTO `sys_logininfor` VALUES (1616088161279025154, '荷塘', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-19 23:00:18'); +INSERT INTO `sys_logininfor` VALUES (1616333993886642178, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-20 15:17:09'); +INSERT INTO `sys_logininfor` VALUES (1616395179604951041, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-20 19:20:17'); +INSERT INTO `sys_logininfor` VALUES (1616658509972148225, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-21 12:46:39'); +INSERT INTO `sys_logininfor` VALUES (1616679603575754753, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-01-21 14:10:29'); +INSERT INTO `sys_logininfor` VALUES (1616723839713071105, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 17:06:15'); +INSERT INTO `sys_logininfor` VALUES (1616725058108051458, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 17:11:06'); +INSERT INTO `sys_logininfor` VALUES (1616725157995401217, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 17:11:30'); +INSERT INTO `sys_logininfor` VALUES (1616725195320512513, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 17:11:39'); +INSERT INTO `sys_logininfor` VALUES (1616733778187702274, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 17:45:45'); +INSERT INTO `sys_logininfor` VALUES (1616733953455083521, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 17:46:27'); +INSERT INTO `sys_logininfor` VALUES (1616769216684277761, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:06:34'); +INSERT INTO `sys_logininfor` VALUES (1616769434628653057, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:07:26'); +INSERT INTO `sys_logininfor` VALUES (1616771721048621057, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:16:31'); +INSERT INTO `sys_logininfor` VALUES (1616771809485520897, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:16:52'); +INSERT INTO `sys_logininfor` VALUES (1616776382002511873, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:35:02'); +INSERT INTO `sys_logininfor` VALUES (1616776670746787841, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:36:11'); +INSERT INTO `sys_logininfor` VALUES (1616776771514941442, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:36:35'); +INSERT INTO `sys_logininfor` VALUES (1616777255063666689, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:38:31'); +INSERT INTO `sys_logininfor` VALUES (1616778667101274113, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:44:07'); +INSERT INTO `sys_logininfor` VALUES (1616778861930889217, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:44:54'); +INSERT INTO `sys_logininfor` VALUES (1616779057741971458, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 20:45:40'); +INSERT INTO `sys_logininfor` VALUES (1616783385886248962, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:02:52'); +INSERT INTO `sys_logininfor` VALUES (1616783822785925122, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:04:36'); +INSERT INTO `sys_logininfor` VALUES (1616784667363508226, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:07:58'); +INSERT INTO `sys_logininfor` VALUES (1616785814900043778, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:12:31'); +INSERT INTO `sys_logininfor` VALUES (1616786974746730498, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:17:08'); +INSERT INTO `sys_logininfor` VALUES (1616792935393779714, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:40:49'); +INSERT INTO `sys_logininfor` VALUES (1616793139652190209, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:41:38'); +INSERT INTO `sys_logininfor` VALUES (1616793834828599298, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 21:44:23'); +INSERT INTO `sys_logininfor` VALUES (1616798445601857538, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 22:02:43'); +INSERT INTO `sys_logininfor` VALUES (1616799944461557762, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 22:08:40'); +INSERT INTO `sys_logininfor` VALUES (1616801436639731714, 'kalashok-pan', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-21 22:14:36'); +INSERT INTO `sys_logininfor` VALUES (1617119682727247873, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-22 19:19:12'); +INSERT INTO `sys_logininfor` VALUES (1617452290749239298, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-01-23 17:20:52'); +INSERT INTO `sys_logininfor` VALUES (1617452302237437953, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-23 17:20:54'); +INSERT INTO `sys_logininfor` VALUES (1617459160608153601, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-23 17:48:09'); +INSERT INTO `sys_logininfor` VALUES (1617476014672207874, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-23 18:55:08'); +INSERT INTO `sys_logininfor` VALUES (1617487785894211586, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-23 19:41:54'); +INSERT INTO `sys_logininfor` VALUES (1617870159047876610, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-24 21:01:19'); +INSERT INTO `sys_logininfor` VALUES (1617870188672245762, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-24 21:01:26'); +INSERT INTO `sys_logininfor` VALUES (1617870460630917121, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-24 21:02:31'); +INSERT INTO `sys_logininfor` VALUES (1617870481854095362, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-24 21:02:36'); +INSERT INTO `sys_logininfor` VALUES (1617870997199839233, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-24 21:04:39'); +INSERT INTO `sys_logininfor` VALUES (1617871024760610817, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-24 21:04:46'); +INSERT INTO `sys_logininfor` VALUES (1617874743417954306, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-01-24 21:19:32'); +INSERT INTO `sys_logininfor` VALUES (1617874884514340866, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-01-24 21:20:06'); +INSERT INTO `sys_logininfor` VALUES (1623326785519239170, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-08 22:24:00'); +INSERT INTO `sys_logininfor` VALUES (1623655905256034305, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-09 20:11:49'); +INSERT INTO `sys_logininfor` VALUES (1623656059384123394, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-09 20:12:25'); +INSERT INTO `sys_logininfor` VALUES (1624273563961913345, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 13:06:10'); +INSERT INTO `sys_logininfor` VALUES (1624274911478542337, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 13:11:31'); +INSERT INTO `sys_logininfor` VALUES (1624274948270977025, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 13:11:40'); +INSERT INTO `sys_logininfor` VALUES (1624279140691734530, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 13:28:19'); +INSERT INTO `sys_logininfor` VALUES (1624279192483000322, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 13:28:32'); +INSERT INTO `sys_logininfor` VALUES (1624281102959112194, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 13:36:07'); +INSERT INTO `sys_logininfor` VALUES (1624281141714481153, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 13:36:17'); +INSERT INTO `sys_logininfor` VALUES (1624290186202460162, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 14:12:13'); +INSERT INTO `sys_logininfor` VALUES (1624290224651644930, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 14:12:22'); +INSERT INTO `sys_logininfor` VALUES (1624292971576832001, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 14:23:17'); +INSERT INTO `sys_logininfor` VALUES (1624293013855416322, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 14:23:27'); +INSERT INTO `sys_logininfor` VALUES (1624299839888044034, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 14:50:35'); +INSERT INTO `sys_logininfor` VALUES (1624299875548016641, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 14:50:43'); +INSERT INTO `sys_logininfor` VALUES (1624300337852592130, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 14:52:33'); +INSERT INTO `sys_logininfor` VALUES (1624300397092941825, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 14:52:47'); +INSERT INTO `sys_logininfor` VALUES (1624307788572286978, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 15:22:10'); +INSERT INTO `sys_logininfor` VALUES (1624307823510839298, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '密码输入错误1次', '2023-02-11 15:22:18'); +INSERT INTO `sys_logininfor` VALUES (1624307855169445890, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 15:22:26'); +INSERT INTO `sys_logininfor` VALUES (1624311473729716225, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 15:36:48'); +INSERT INTO `sys_logininfor` VALUES (1624311507552583682, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 15:36:56'); +INSERT INTO `sys_logininfor` VALUES (1624312003495477250, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 15:38:55'); +INSERT INTO `sys_logininfor` VALUES (1624312062467391490, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 15:39:09'); +INSERT INTO `sys_logininfor` VALUES (1624316607964659714, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 15:57:12'); +INSERT INTO `sys_logininfor` VALUES (1624317686106300417, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 16:01:29'); +INSERT INTO `sys_logininfor` VALUES (1624317735733305345, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 16:01:41'); +INSERT INTO `sys_logininfor` VALUES (1624321148902805505, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-11 16:15:15'); +INSERT INTO `sys_logininfor` VALUES (1624321185028345857, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-11 16:15:24'); +INSERT INTO `sys_logininfor` VALUES (1624626861617258497, '测试666', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '注册成功', '2023-02-12 12:30:03'); +INSERT INTO `sys_logininfor` VALUES (1624626862540005377, '测试666', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-12 12:30:03'); +INSERT INTO `sys_logininfor` VALUES (1624627471531974658, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-12 12:32:28'); +INSERT INTO `sys_logininfor` VALUES (1625478260932476929, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-14 20:53:12'); +INSERT INTO `sys_logininfor` VALUES (1625487104853147650, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-14 21:28:21'); +INSERT INTO `sys_logininfor` VALUES (1625778036974571522, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-15 16:44:24'); +INSERT INTO `sys_logininfor` VALUES (1625787163205455874, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-15 17:20:40'); +INSERT INTO `sys_logininfor` VALUES (1625844261406744577, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-15 21:07:33'); +INSERT INTO `sys_logininfor` VALUES (1625845496801251330, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-15 21:12:28'); +INSERT INTO `sys_logininfor` VALUES (1625846201507237890, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-15 21:15:16'); +INSERT INTO `sys_logininfor` VALUES (1625846241772556289, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-15 21:15:25'); +INSERT INTO `sys_logininfor` VALUES (1625847087126138881, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-15 21:18:47'); +INSERT INTO `sys_logininfor` VALUES (1625847130541379586, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-15 21:18:57'); +INSERT INTO `sys_logininfor` VALUES (1626082520447610882, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-16 12:54:19'); +INSERT INTO `sys_logininfor` VALUES (1626093204354916353, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-16 13:36:46'); +INSERT INTO `sys_logininfor` VALUES (1626500769895186433, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-17 16:36:17'); +INSERT INTO `sys_logininfor` VALUES (1627233076977430530, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-19 17:06:13'); +INSERT INTO `sys_logininfor` VALUES (1627236400111906818, 'admin', '127.0.0.1', '内网IP', 'Chrome', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-19 17:19:25'); +INSERT INTO `sys_logininfor` VALUES (1627286783274323969, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-02-19 20:39:37'); +INSERT INTO `sys_logininfor` VALUES (1627286799334313986, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-19 20:39:41'); +INSERT INTO `sys_logininfor` VALUES (1627497155520401409, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-20 10:35:34'); +INSERT INTO `sys_logininfor` VALUES (1627529795665432577, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-20 12:45:16'); +INSERT INTO `sys_logininfor` VALUES (1627613052394311682, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-20 18:16:06'); +INSERT INTO `sys_logininfor` VALUES (1627635820544430082, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-20 19:46:34'); +INSERT INTO `sys_logininfor` VALUES (1627640695986601986, 'admin', '127.0.0.1', '内网IP', 'Chrome', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-02-20 20:05:57'); +INSERT INTO `sys_logininfor` VALUES (1627640707097313282, 'admin', '127.0.0.1', '内网IP', 'Chrome', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-20 20:05:59'); +INSERT INTO `sys_logininfor` VALUES (1627852916217999361, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-21 10:09:14'); +INSERT INTO `sys_logininfor` VALUES (1627991363066818561, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-21 19:19:22'); +INSERT INTO `sys_logininfor` VALUES (1627995735364497410, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-21 19:36:45'); +INSERT INTO `sys_logininfor` VALUES (1628027130027794434, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-21 21:41:30'); +INSERT INTO `sys_logininfor` VALUES (1628215384534507522, 'admin', '4.2.2.2', 'XX XX', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 10:09:33'); +INSERT INTO `sys_logininfor` VALUES (1628251678241230849, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 12:33:46'); +INSERT INTO `sys_logininfor` VALUES (1628267482282201090, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 13:36:34'); +INSERT INTO `sys_logininfor` VALUES (1628324430931300354, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 17:22:52'); +INSERT INTO `sys_logininfor` VALUES (1628370965844987905, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 20:27:47'); +INSERT INTO `sys_logininfor` VALUES (1628380212242694145, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 21:04:31'); +INSERT INTO `sys_logininfor` VALUES (1628380608164020226, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-22 21:06:06'); +INSERT INTO `sys_logininfor` VALUES (1628380627105497089, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-22 21:06:10'); +INSERT INTO `sys_logininfor` VALUES (1628608838607351810, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 12:13:00'); +INSERT INTO `sys_logininfor` VALUES (1628622541339799554, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 13:07:27'); +INSERT INTO `sys_logininfor` VALUES (1628641061452693506, 'admin', '4.2.2.2', 'XX XX', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码已失效', '2023-02-23 14:21:02'); +INSERT INTO `sys_logininfor` VALUES (1628641080817795073, 'admin', '4.2.2.2', 'XX XX', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:21:07'); +INSERT INTO `sys_logininfor` VALUES (1628648705408110594, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 14:51:25'); +INSERT INTO `sys_logininfor` VALUES (1628648746008973313, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:51:35'); +INSERT INTO `sys_logininfor` VALUES (1628648839386763266, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 14:51:57'); +INSERT INTO `sys_logininfor` VALUES (1628648858944802817, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:52:01'); +INSERT INTO `sys_logininfor` VALUES (1628648998657069057, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 14:52:35'); +INSERT INTO `sys_logininfor` VALUES (1628649030479253506, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:52:42'); +INSERT INTO `sys_logininfor` VALUES (1628649172917817346, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 14:53:16'); +INSERT INTO `sys_logininfor` VALUES (1628649188986195970, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:53:20'); +INSERT INTO `sys_logininfor` VALUES (1628649648216346626, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 14:55:10'); +INSERT INTO `sys_logininfor` VALUES (1628649681875636226, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:55:18'); +INSERT INTO `sys_logininfor` VALUES (1628650094016335873, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 14:56:56'); +INSERT INTO `sys_logininfor` VALUES (1628650128174747649, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 14:57:04'); +INSERT INTO `sys_logininfor` VALUES (1628651389901090818, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 15:02:05'); +INSERT INTO `sys_logininfor` VALUES (1628651424604762114, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 15:02:13'); +INSERT INTO `sys_logininfor` VALUES (1628652200286855169, 'test', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 15:05:18'); +INSERT INTO `sys_logininfor` VALUES (1628652238660542466, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 15:05:27'); +INSERT INTO `sys_logininfor` VALUES (1628656122997088257, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-23 15:20:53'); +INSERT INTO `sys_logininfor` VALUES (1628656138100776962, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 15:20:57'); +INSERT INTO `sys_logininfor` VALUES (1628657546392870913, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 15:26:33'); +INSERT INTO `sys_logininfor` VALUES (1628668026226319362, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 16:08:11'); +INSERT INTO `sys_logininfor` VALUES (1628734404769722370, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-23 20:31:57'); +INSERT INTO `sys_logininfor` VALUES (1629470494346457090, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-25 21:16:55'); +INSERT INTO `sys_logininfor` VALUES (1629470667294388226, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-02-25 21:17:36'); +INSERT INTO `sys_logininfor` VALUES (1629470702673342466, 'test1', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-25 21:17:44'); +INSERT INTO `sys_logininfor` VALUES (1630181617853112321, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-27 20:22:40'); +INSERT INTO `sys_logininfor` VALUES (1630184528473595905, 'admin', '127.0.0.1', '内网IP', 'Chrome', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-27 20:34:14'); +INSERT INTO `sys_logininfor` VALUES (1630188661712723970, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-27 20:50:39'); +INSERT INTO `sys_logininfor` VALUES (1630392843744854018, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 10:22:00'); +INSERT INTO `sys_logininfor` VALUES (1630393204249477121, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 10:23:26'); +INSERT INTO `sys_logininfor` VALUES (1630408383414779905, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 11:23:45'); +INSERT INTO `sys_logininfor` VALUES (1630510919807143938, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 18:11:11'); +INSERT INTO `sys_logininfor` VALUES (1630522549005713409, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 18:57:24'); +INSERT INTO `sys_logininfor` VALUES (1630539374959529986, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 20:04:16'); +INSERT INTO `sys_logininfor` VALUES (1630542760656281601, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 20:17:43'); +INSERT INTO `sys_logininfor` VALUES (1630572334056251393, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-02-28 22:15:14'); +INSERT INTO `sys_logininfor` VALUES (1630905035464417282, 'admin', '4.2.2.2', ' ', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-01 20:17:16'); +INSERT INTO `sys_logininfor` VALUES (1633693458906517505, 'admin', '127.0.0.1', '内网IP', 'Chrome', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 12:57:28'); +INSERT INTO `sys_logininfor` VALUES (1633693502934126594, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 12:57:38'); +INSERT INTO `sys_logininfor` VALUES (1633727462414266369, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 15:12:35'); +INSERT INTO `sys_logininfor` VALUES (1633729052562993153, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 15:18:54'); +INSERT INTO `sys_logininfor` VALUES (1633736891427782658, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 15:50:03'); +INSERT INTO `sys_logininfor` VALUES (1633792347986735106, 'test1', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 19:30:25'); +INSERT INTO `sys_logininfor` VALUES (1633799616837259266, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-09 19:59:18'); +INSERT INTO `sys_logininfor` VALUES (1634120790859378690, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '验证码错误', '2023-03-10 17:15:32'); +INSERT INTO `sys_logininfor` VALUES (1634120804230819842, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-10 17:15:35'); +INSERT INTO `sys_logininfor` VALUES (1634126648821501954, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-10 17:38:48'); +INSERT INTO `sys_logininfor` VALUES (1634423882343559170, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-11 13:19:54'); +INSERT INTO `sys_logininfor` VALUES (1634425402141224962, 'test', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-11 13:25:57'); +INSERT INTO `sys_logininfor` VALUES (1634775531981496321, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-03-12 12:37:14'); +INSERT INTO `sys_logininfor` VALUES (1647072023224012801, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-15 10:59:06'); +INSERT INTO `sys_logininfor` VALUES (1647079066316050434, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-15 11:27:05'); +INSERT INTO `sys_logininfor` VALUES (1647486221905068034, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-16 14:24:59'); +INSERT INTO `sys_logininfor` VALUES (1647501372741947393, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2023-04-16 15:25:11'); +INSERT INTO `sys_logininfor` VALUES (1647501397098270722, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-16 15:25:17'); +INSERT INTO `sys_logininfor` VALUES (1647906314682142722, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-17 18:14:17'); +INSERT INTO `sys_logininfor` VALUES (1647906967932485634, 'test', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-17 18:16:52'); +INSERT INTO `sys_logininfor` VALUES (1647910507568451585, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-17 18:30:56'); +INSERT INTO `sys_logininfor` VALUES (1647910774464598017, 'admin', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2023-04-17 18:32:00'); + +-- ---------------------------- +-- Table structure for sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_menu`; +CREATE TABLE `sys_menu` ( + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + `menu_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '菜单名称', + `parent_id` bigint(20) NULL DEFAULT 0 COMMENT '父菜单ID', + `order_num` int(4) NULL DEFAULT 0 COMMENT '显示顺序', + `path` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '路由地址', + `component` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组件路径', + `query_param` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '路由参数', + `is_frame` int(1) NULL DEFAULT 1 COMMENT '是否为外链(0是 1否)', + `is_cache` int(1) NULL DEFAULT 0 COMMENT '是否缓存(0缓存 1不缓存)', + `menu_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)', + `visible` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '显示状态(0显示 1隐藏)', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '菜单状态(0正常 1停用)', + `perms` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限标识', + `icon` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '#' COMMENT '菜单图标', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '备注', + PRIMARY KEY (`menu_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '菜单权限表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_menu +-- ---------------------------- +INSERT INTO `sys_menu` VALUES (1, '系统管理', 0, 5, 'system', NULL, '', 1, 0, 'M', '0', '0', '', 'system', 'admin', '2023-01-05 19:54:19', 'admin', '2023-02-14 22:03:37', '系统管理目录'); +INSERT INTO `sys_menu` VALUES (2, '系统监控', 0, 5, 'monitor', NULL, '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', '2023-01-05 19:54:19', 'admin', '2023-02-14 22:03:09', '系统监控目录'); +INSERT INTO `sys_menu` VALUES (3, '系统工具', 0, 6, 'tool', NULL, '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-11 13:28:57', '系统工具目录'); +INSERT INTO `sys_menu` VALUES (5, '测试菜单', 0, 7, 'demo', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'star', 'admin', '2023-01-05 19:54:34', 'admin', '2023-01-11 13:29:03', ''); +INSERT INTO `sys_menu` VALUES (100, '用户管理', 1, 1, 'user', 'system/user/index', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', '2023-01-05 19:54:19', '', NULL, '用户管理菜单'); +INSERT INTO `sys_menu` VALUES (101, '角色管理', 1, 2, 'role', 'system/role/index', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', '2023-01-05 19:54:19', '', NULL, '角色管理菜单'); +INSERT INTO `sys_menu` VALUES (102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', '2023-01-05 19:54:19', '', NULL, '菜单管理菜单'); +INSERT INTO `sys_menu` VALUES (103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', '2023-01-05 19:54:19', '', NULL, '部门管理菜单'); +INSERT INTO `sys_menu` VALUES (104, '岗位管理', 1, 5, 'post', 'system/post/index', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', '2023-01-05 19:54:19', '', NULL, '岗位管理菜单'); +INSERT INTO `sys_menu` VALUES (105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', '2023-01-05 19:54:19', '', NULL, '字典管理菜单'); +INSERT INTO `sys_menu` VALUES (106, '参数设置', 1, 7, 'config', 'system/config/index', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', '2023-01-05 19:54:19', '', NULL, '参数设置菜单'); +INSERT INTO `sys_menu` VALUES (107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', '2023-01-05 19:54:19', '', NULL, '通知公告菜单'); +INSERT INTO `sys_menu` VALUES (108, '日志管理', 1, 9, 'log', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', '2023-01-05 19:54:19', '', NULL, '日志管理菜单'); +INSERT INTO `sys_menu` VALUES (109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', '2023-01-05 19:54:19', '', NULL, '在线用户菜单'); +INSERT INTO `sys_menu` VALUES (112, '缓存列表', 2, 6, 'cacheList', 'monitor/cache/list', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', '2023-01-05 19:54:19', '', NULL, '缓存列表菜单'); +INSERT INTO `sys_menu` VALUES (113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', '2023-01-05 19:54:19', '', NULL, '缓存监控菜单'); +INSERT INTO `sys_menu` VALUES (114, '表单构建', 3, 1, 'build', 'tool/build/index', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', '2023-01-05 19:54:19', '', NULL, '表单构建菜单'); +INSERT INTO `sys_menu` VALUES (115, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', '2023-01-05 19:54:19', '', NULL, '代码生成菜单'); +INSERT INTO `sys_menu` VALUES (118, '文件管理', 1, 10, 'oss', 'system/oss/index', '', 1, 0, 'C', '0', '0', 'system:oss:list', 'upload', 'admin', '2023-01-05 19:54:19', '', NULL, '文件管理菜单'); +INSERT INTO `sys_menu` VALUES (120, '任务调度中心', 2, 5, 'XxlJob', 'monitor/xxljob/index', '', 1, 0, 'C', '0', '0', 'monitor:xxljob:list', 'job', 'admin', '2023-01-05 19:54:19', '', NULL, 'Xxl-Job控制台菜单'); +INSERT INTO `sys_menu` VALUES (500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', '2023-01-05 19:54:19', '', NULL, '操作日志菜单'); +INSERT INTO `sys_menu` VALUES (501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2023-01-05 19:54:19', '', NULL, '登录日志菜单'); +INSERT INTO `sys_menu` VALUES (1001, '用户查询', 100, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1002, '用户新增', 100, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1003, '用户修改', 100, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1004, '用户删除', 100, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1005, '用户导出', 100, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1006, '用户导入', 100, 6, '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1007, '重置密码', 100, 7, '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1008, '角色查询', 101, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1009, '角色新增', 101, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1010, '角色修改', 101, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1011, '角色删除', 101, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1012, '角色导出', 101, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1013, '菜单查询', 102, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1014, '菜单新增', 102, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1015, '菜单修改', 102, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1016, '菜单删除', 102, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1017, '部门查询', 103, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1018, '部门新增', 103, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1019, '部门修改', 103, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1020, '部门删除', 103, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1021, '岗位查询', 104, 1, '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1022, '岗位新增', 104, 2, '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1023, '岗位修改', 104, 3, '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1024, '岗位删除', 104, 4, '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1025, '岗位导出', 104, 5, '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1026, '字典查询', 105, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1027, '字典新增', 105, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1028, '字典修改', 105, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1029, '字典删除', 105, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1030, '字典导出', 105, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1031, '参数查询', 106, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1032, '参数新增', 106, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1033, '参数修改', 106, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1034, '参数删除', 106, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1035, '参数导出', 106, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1036, '公告查询', 107, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1037, '公告新增', 107, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1038, '公告修改', 107, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1039, '公告删除', 107, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1040, '操作查询', 500, 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1041, '操作删除', 500, 2, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1042, '日志导出', 500, 4, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1043, '登录查询', 501, 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1044, '登录删除', 501, 2, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1045, '日志导出', 501, 3, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1046, '在线查询', 109, 1, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1047, '批量强退', 109, 2, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1048, '单条强退', 109, 3, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1050, '账户解锁', 501, 4, '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1055, '生成查询', 115, 1, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1056, '生成修改', 115, 2, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1057, '生成删除', 115, 3, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1058, '导入代码', 115, 2, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1059, '预览代码', 115, 4, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1060, '生成代码', 115, 5, '#', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1500, '测试单表', 5, 1, 'demo', 'demo/demo/index', NULL, 1, 0, 'C', '0', '0', 'demo:demo:list', '#', 'admin', '2023-01-05 19:54:34', '', NULL, '测试单表菜单'); +INSERT INTO `sys_menu` VALUES (1501, '测试单表查询', 1500, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:demo:query', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1502, '测试单表新增', 1500, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:demo:add', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1503, '测试单表修改', 1500, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:demo:edit', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1504, '测试单表删除', 1500, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:demo:remove', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1505, '测试单表导出', 1500, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:demo:export', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1506, '测试树表', 5, 1, 'tree', 'demo/tree/index', NULL, 1, 0, 'C', '0', '0', 'demo:tree:list', '#', 'admin', '2023-01-05 19:54:34', '', NULL, '测试树表菜单'); +INSERT INTO `sys_menu` VALUES (1507, '测试树表查询', 1506, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:tree:query', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1508, '测试树表新增', 1506, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:tree:add', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1509, '测试树表修改', 1506, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:tree:edit', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1510, '测试树表删除', 1506, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:tree:remove', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1511, '测试树表导出', 1506, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'demo:tree:export', '#', 'admin', '2023-01-05 19:54:34', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1600, '文件查询', 118, 1, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:query', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1601, '文件上传', 118, 2, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:upload', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1602, '文件下载', 118, 3, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:download', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1603, '文件删除', 118, 4, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:remove', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1604, '配置添加', 118, 5, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:add', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1605, '配置编辑', 118, 6, '#', '', '', 1, 0, 'F', '0', '0', 'system:oss:edit', '#', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1610972802922405889, '文章管理', 0, 1, 'article', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'education', 'admin', '2023-01-05 20:13:41', 'admin', '2023-01-10 18:21:29', ''); +INSERT INTO `sys_menu` VALUES (1610973263779946497, '发布文章', 1610972802922405889, 1, 'articles', 'article/article/index', NULL, 1, 0, 'C', '0', '0', NULL, 'form', 'admin', '2023-01-05 20:15:31', 'admin', '2023-01-05 20:22:40', ''); +INSERT INTO `sys_menu` VALUES (1611336461808898048, '文章列表', 1610972802922405889, 2, 'article', 'article/articleList/index', NULL, 1, 1, 'C', '0', '0', 'article:article:list', 'list', 'admin', '2023-01-06 20:21:38', 'admin', '2023-01-09 23:18:57', '文章列表菜单'); +INSERT INTO `sys_menu` VALUES (1611336461808898049, '文章列表查询', 1611336461808898048, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'article:article:query', '#', 'admin', '2023-01-06 20:21:38', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611336461808898050, '文章列表新增', 1611336461808898048, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'article:article:add', '#', 'admin', '2023-01-06 20:21:38', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611336461808898051, '文章列表修改', 1611336461808898048, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'article:article:edit', '#', 'admin', '2023-01-06 20:21:38', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611336461808898052, '文章列表删除', 1611336461808898048, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'article:article:remove', '#', 'admin', '2023-01-06 20:21:38', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611336461808898053, '文章列表导出', 1611336461808898048, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'article:article:export', '#', 'admin', '2023-01-06 20:21:38', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611613727679938560, '分类管理', 1610972802922405889, 3, 'category', 'category/category/index', NULL, 1, 0, 'C', '0', '0', 'category:category:list', 'table', 'admin', '2023-01-07 14:46:40', 'admin', '2023-01-09 23:19:06', '分类管理菜单'); +INSERT INTO `sys_menu` VALUES (1611613727679938561, '分类管理查询', 1611613727679938560, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'category:category:query', '#', 'admin', '2023-01-07 14:46:40', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611613727679938562, '分类管理新增', 1611613727679938560, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'category:category:add', '#', 'admin', '2023-01-07 14:46:40', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611613727679938563, '分类管理修改', 1611613727679938560, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'category:category:edit', '#', 'admin', '2023-01-07 14:46:40', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611613727679938564, '分类管理删除', 1611613727679938560, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'category:category:remove', '#', 'admin', '2023-01-07 14:46:40', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611613727679938565, '分类管理导出', 1611613727679938560, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'category:category:export', '#', 'admin', '2023-01-07 14:46:40', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611975928588574720, '标签管理', 1610972802922405889, 4, 'tag', 'tag/tag/index', NULL, 1, 0, 'C', '0', '0', 'tag:tag:list', 'icon', 'admin', '2023-01-08 14:57:33', 'admin', '2023-01-09 23:19:11', '标签管理菜单'); +INSERT INTO `sys_menu` VALUES (1611975928588574721, '标签管理查询', 1611975928588574720, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'tag:tag:query', '#', 'admin', '2023-01-08 14:57:33', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611975928588574722, '标签管理新增', 1611975928588574720, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'tag:tag:add', '#', 'admin', '2023-01-08 14:57:33', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611975928588574723, '标签管理修改', 1611975928588574720, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'tag:tag:edit', '#', 'admin', '2023-01-08 14:57:33', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611975928588574724, '标签管理删除', 1611975928588574720, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'tag:tag:remove', '#', 'admin', '2023-01-08 14:57:33', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1611975928588574725, '标签管理导出', 1611975928588574720, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'tag:tag:export', '#', 'admin', '2023-01-08 14:57:33', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1612801785548894209, '消息管理', 0, 2, '/message', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'message', 'admin', '2023-01-10 21:21:25', 'admin', '2023-01-11 13:28:26', ''); +INSERT INTO `sys_menu` VALUES (1612810100827877376, '评论管理', 1612801785548894209, 1, 'comment', 'comment/comment/index', NULL, 1, 0, 'C', '0', '0', 'comment:comment:list', 'documentation', 'admin', '2023-01-10 21:58:57', 'admin', '2023-01-11 13:27:41', '评论管理菜单'); +INSERT INTO `sys_menu` VALUES (1612810100827877377, '评论管理查询', 1612810100827877376, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'comment:comment:query', '#', 'admin', '2023-01-10 21:58:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1612810100827877378, '评论管理新增', 1612810100827877376, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'comment:comment:add', '#', 'admin', '2023-01-10 21:58:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1612810100827877379, '评论管理修改', 1612810100827877376, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'comment:comment:edit', '#', 'admin', '2023-01-10 21:58:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1612810100827877380, '评论管理删除', 1612810100827877376, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'comment:comment:remove', '#', 'admin', '2023-01-10 21:58:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1612810100827877381, '评论管理导出', 1612810100827877376, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'comment:comment:export', '#', 'admin', '2023-01-10 21:58:57', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613049235916275714, '个人中心', 0, 10, 'user/profile', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'user', 'admin', '2023-01-11 13:44:42', 'admin', '2023-01-11 13:45:12', ''); +INSERT INTO `sys_menu` VALUES (1613098351056703488, '留言管理', 1612801785548894209, 2, 'message', 'message/message/index', NULL, 1, 0, 'C', '0', '0', 'message:message:list', 'checkbox', 'admin', '2023-01-11 17:03:25', 'admin', '2023-01-11 17:31:31', '留言管理菜单'); +INSERT INTO `sys_menu` VALUES (1613098351056703489, '留言管理查询', 1613098351056703488, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'message:message:query', '#', 'admin', '2023-01-11 17:03:25', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613098351056703490, '留言管理新增', 1613098351056703488, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'message:message:add', '#', 'admin', '2023-01-11 17:03:25', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613098351056703491, '留言管理修改', 1613098351056703488, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'message:message:edit', '#', 'admin', '2023-01-11 17:03:25', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613098351056703492, '留言管理删除', 1613098351056703488, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'message:message:remove', '#', 'admin', '2023-01-11 17:03:25', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613098351056703493, '留言管理导出', 1613098351056703488, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'message:message:export', '#', 'admin', '2023-01-11 17:03:25', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613139021339353090, '界面管理', 0, 3, '/website', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'theme', 'admin', '2023-01-11 19:41:28', 'admin', '2023-01-11 19:41:28', ''); +INSERT INTO `sys_menu` VALUES (1613157470488813570, '网站管理', 1613139021339353090, 1, 'website', 'website', '', 1, 1, 'C', '0', '0', NULL, 'international', 'admin', '2023-01-11 20:54:47', 'admin', '2023-01-11 20:55:15', ''); +INSERT INTO `sys_menu` VALUES (1613398656495439872, '页面管理', 1613139021339353090, 2, 'page', 'page/index', NULL, 1, 0, 'C', '0', '0', 'page:page:list', 'education', 'admin', '2023-01-12 12:55:15', 'admin', '2023-01-12 13:37:39', '页面管理菜单'); +INSERT INTO `sys_menu` VALUES (1613398656495439873, '页面管理查询', 1613398656495439872, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'page:page:query', '#', 'admin', '2023-01-12 12:55:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613398656495439874, '页面管理新增', 1613398656495439872, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'page:page:add', '#', 'admin', '2023-01-12 12:55:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613398656495439875, '页面管理修改', 1613398656495439872, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'page:page:edit', '#', 'admin', '2023-01-12 12:55:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613398656495439876, '页面管理删除', 1613398656495439872, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'page:page:remove', '#', 'admin', '2023-01-12 12:55:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613398656495439877, '页面管理导出', 1613398656495439872, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'page:page:export', '#', 'admin', '2023-01-12 12:55:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613408736209010688, '友链管理', 1613139021339353090, 3, 'friendLink', 'friendLink/friendLink/index', NULL, 1, 0, 'C', '0', '0', 'friendLink:friendLink:list', 'people', 'admin', '2023-01-12 13:36:15', 'admin', '2023-01-12 13:37:50', '友链管理菜单'); +INSERT INTO `sys_menu` VALUES (1613408736209010689, '友链管理查询', 1613408736209010688, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'friendLink:friendLink:query', '#', 'admin', '2023-01-12 13:36:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613408736209010690, '友链管理新增', 1613408736209010688, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'friendLink:friendLink:add', '#', 'admin', '2023-01-12 13:36:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613408736209010691, '友链管理修改', 1613408736209010688, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'friendLink:friendLink:edit', '#', 'admin', '2023-01-12 13:36:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613408736209010692, '友链管理删除', 1613408736209010688, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'friendLink:friendLink:remove', '#', 'admin', '2023-01-12 13:36:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613408736209010693, '友链管理导出', 1613408736209010688, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'friendLink:friendLink:export', '#', 'admin', '2023-01-12 13:36:15', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613813815185510401, '说说管理', 0, 5, 'talk', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'wechat', 'admin', '2023-01-13 16:22:51', 'admin', '2023-01-13 16:22:51', ''); +INSERT INTO `sys_menu` VALUES (1613816542531686400, '说说列表', 1613813815185510401, 2, 'talks', 'talk/talkList/index', NULL, 1, 0, 'C', '0', '0', 'talk:talk:list', 'tree-table', 'admin', '2023-01-13 16:37:32', 'admin', '2023-01-14 12:52:36', '说说管理菜单'); +INSERT INTO `sys_menu` VALUES (1613816542531686401, '说说管理查询', 1613816542531686400, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'talk:talk:query', '#', 'admin', '2023-01-13 16:37:32', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613816542531686402, '说说管理新增', 1613816542531686400, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'talk:talk:add', '#', 'admin', '2023-01-13 16:37:32', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613816542531686403, '说说管理修改', 1613816542531686400, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'talk:talk:edit', '#', 'admin', '2023-01-13 16:37:32', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613816542531686404, '说说管理删除', 1613816542531686400, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'talk:talk:remove', '#', 'admin', '2023-01-13 16:37:32', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613816542531686405, '说说管理导出', 1613816542531686400, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'talk:talk:export', '#', 'admin', '2023-01-13 16:37:32', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1613861852100489217, '发布说说', 1613813815185510401, 1, 'talk', 'talk/talk', NULL, 1, 0, 'C', '0', '0', NULL, 'druid', 'admin', '2023-01-13 19:33:44', 'admin', '2023-01-13 19:34:54', ''); +INSERT INTO `sys_menu` VALUES (1625495355317592066, '云端配置', 0, 4, 'system/oss-config/index', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'upload', 'admin', '2023-02-14 22:01:08', 'admin', '2023-02-14 22:04:01', ''); +INSERT INTO `sys_menu` VALUES (1627233395924889602, '关于我', 1613139021339353090, 4, 'about', 'about/About.vue', NULL, 1, 0, 'C', '0', '0', NULL, 'theme', 'admin', '2023-02-19 17:07:29', 'admin', '2023-02-19 17:10:50', ''); +INSERT INTO `sys_menu` VALUES (1627642998340730881, '相册管理', 0, 2, 'album', NULL, NULL, 1, 0, 'M', '0', '0', NULL, 'build', 'admin', '2023-02-20 20:15:06', 'admin', '2023-02-20 20:15:06', ''); +INSERT INTO `sys_menu` VALUES (1627643112476131328, '相册列表', 1627642998340730881, 1, 'album', 'album/album/Album', NULL, 1, 0, 'C', '0', '0', 'album:album:list', 'list', 'admin', '2023-02-20 20:16:08', 'admin', '2023-02-21 19:42:07', '相册管理菜单'); +INSERT INTO `sys_menu` VALUES (1627643112476131329, '相册管理查询', 1627643112476131328, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'album:album:query', '#', 'admin', '2023-02-20 20:16:08', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1627643112476131330, '相册管理新增', 1627643112476131328, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'album:album:add', '#', 'admin', '2023-02-20 20:16:08', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1627643112476131331, '相册管理修改', 1627643112476131328, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'album:album:edit', '#', 'admin', '2023-02-20 20:16:08', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1627643112476131332, '相册管理删除', 1627643112476131328, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'album:album:remove', '#', 'admin', '2023-02-20 20:16:08', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1627643112476131333, '相册管理导出', 1627643112476131328, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'album:album:export', '#', 'admin', '2023-02-20 20:16:08', '', NULL, ''); +INSERT INTO `sys_menu` VALUES (1627996831193526274, '照片管理', 1627642998340730881, 2, 'photo', 'album/album/Photo', '', 1, 0, 'C', '1', '0', NULL, 'eye-open', 'admin', '2023-02-21 19:41:06', 'admin', '2023-02-22 21:46:53', ''); + +-- ---------------------------- +-- Table structure for sys_notice +-- ---------------------------- +DROP TABLE IF EXISTS `sys_notice`; +CREATE TABLE `sys_notice` ( + `notice_id` bigint(20) NOT NULL COMMENT '公告ID', + `notice_title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '公告标题', + `notice_type` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '公告类型(1通知 2公告)', + `notice_content` longblob NULL COMMENT '公告内容', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '公告状态(0正常 1关闭)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`notice_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '通知公告表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_notice +-- ---------------------------- +INSERT INTO `sys_notice` VALUES (1, '温馨提醒:2018-07-01 新版本发布啦', '2', 0xE696B0E78988E69CACE58685E5AEB9, '0', 'admin', '2023-01-05 19:54:19', '', NULL, '管理员'); +INSERT INTO `sys_notice` VALUES (2, '维护通知:2018-07-01 系统凌晨维护', '1', 0xE7BBB4E68AA4E58685E5AEB9, '0', 'admin', '2023-01-05 19:54:19', '', NULL, '管理员'); + +-- ---------------------------- +-- Table structure for sys_oper_log +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oper_log`; +CREATE TABLE `sys_oper_log` ( + `oper_id` bigint(20) NOT NULL COMMENT '日志主键', + `title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '模块标题', + `business_type` int(2) NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)', + `method` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '方法名称', + `request_method` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求方式', + `operator_type` int(1) NULL DEFAULT 0 COMMENT '操作类别(0其它 1后台用户 2手机端用户)', + `oper_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作人员', + `dept_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '部门名称', + `oper_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求URL', + `oper_ip` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '主机地址', + `oper_location` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作地点', + `oper_param` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求参数', + `json_result` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '返回参数', + `status` int(1) NULL DEFAULT 0 COMMENT '操作状态(0正常 1异常)', + `error_msg` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '错误消息', + `oper_time` datetime NULL DEFAULT NULL COMMENT '操作时间', + PRIMARY KEY (`oper_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '操作日志记录' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_oper_log +-- ---------------------------- +INSERT INTO `sys_oper_log` VALUES (1610968366145691649, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/117', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 19:56:03'); +INSERT INTO `sys_oper_log` VALUES (1610972802922405890, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:13:41\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-05 20:13:41\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1610972802922405889\",\"menuName\":\"文章管理\",\"orderNum\":6,\"path\":\"articles\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"education\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 20:13:41'); +INSERT INTO `sys_oper_log` VALUES (1610973263779946498, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:15:31\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-05 20:15:31\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1610973263779946497\",\"menuName\":\"发布文章\",\"orderNum\":1,\"path\":\"articles\",\"component\":\"articles\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"form\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 20:15:31'); +INSERT INTO `sys_oper_log` VALUES (1610974189890658305, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:15:31\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-05 20:19:11\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1610973263779946497\",\"menuName\":\"发布文章\",\"orderNum\":1,\"path\":\"articles\",\"component\":\"article/Article.vue\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"form\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 20:19:12'); +INSERT INTO `sys_oper_log` VALUES (1610974340449394689, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:13:41\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-05 20:19:47\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1610972802922405889\",\"menuName\":\"文章管理\",\"orderNum\":6,\"path\":\"article\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"education\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 20:19:48'); +INSERT INTO `sys_oper_log` VALUES (1610974367708176386, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:15:31\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-05 20:19:54\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1610973263779946497\",\"menuName\":\"发布文章\",\"orderNum\":1,\"path\":\"articles\",\"component\":\"article/Article.vue\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"form\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 20:19:54'); +INSERT INTO `sys_oper_log` VALUES (1610975062465273857, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:15:31\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-05 20:22:40\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1610973263779946497\",\"menuName\":\"发布文章\",\"orderNum\":1,\"path\":\"articles\",\"component\":\"article/article/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"form\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-05 20:22:40'); +INSERT INTO `sys_oper_log` VALUES (1611328955581820930, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_article\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 19:48:55'); +INSERT INTO `sys_oper_log` VALUES (1611329514472828930, '字典类型', 1, 'com.zhi.web.controller.system.SysDictTypeController.add()', 'POST', 1, 'admin', '', '/system/dict/type', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:51:07\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:51:07\",\"dictId\":\"1611329514405720065\",\"dictName\":\"文章类型\",\"dictType\":\"article_type\",\"status\":\"0\",\"remark\":\"文章类型\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 19:51:08'); +INSERT INTO `sys_oper_log` VALUES (1611329875921170433, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:52:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:52:34\",\"dictCode\":\"1611329875858255874\",\"dictSort\":1,\"dictLabel\":\"原创\",\"dictValue\":\"1\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"default\",\"isDefault\":null,\"status\":\"0\",\"remark\":\"原创\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 19:52:34'); +INSERT INTO `sys_oper_log` VALUES (1611329966916595714, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:52:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:52:55\",\"dictCode\":\"1611329966849486850\",\"dictSort\":2,\"dictLabel\":\"转载\",\"dictValue\":\"2\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"default\",\"isDefault\":null,\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 19:52:56'); +INSERT INTO `sys_oper_log` VALUES (1611330010747072514, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:53:06\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:53:06\",\"dictCode\":\"1611330010747072513\",\"dictSort\":3,\"dictLabel\":\"翻译\",\"dictValue\":\"3\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"default\",\"isDefault\":null,\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 19:53:06'); +INSERT INTO `sys_oper_log` VALUES (1611331545770061826, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:59:12\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611328955321774082\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.system\",\"moduleName\":\"system\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:59:12\",\"columnId\":\"1611328955384688642\",\"tableId\":\"1611328955321774082\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:59:12\",\"columnId\":\"1611328955384688643\",\"tableId\":\"1611328955321774082\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 19:59:12\",\"columnId\":\"1611328955384688644\",\"tableId\":\"1611328955321774082\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 19:59:12'); +INSERT INTO `sys_oper_log` VALUES (1611331586249289730, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_article\"}', '', 0, '', '2023-01-06 19:59:22'); +INSERT INTO `sys_oper_log` VALUES (1611332134113472514, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:01:32\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611328955321774082\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.article\",\"moduleName\":\"system\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:01:32\",\"columnId\":\"1611328955384688642\",\"tableId\":\"1611328955321774082\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:01:32\",\"columnId\":\"1611328955384688643\",\"tableId\":\"1611328955321774082\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:01:32\",\"columnId\":\"1611328955384688644\",\"tableId\":\"1611328955321774082\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:01:33'); +INSERT INTO `sys_oper_log` VALUES (1611332431456071682, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:02:43\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611328955321774082\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"system\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:02:43\",\"columnId\":\"1611328955384688642\",\"tableId\":\"1611328955321774082\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:02:43\",\"columnId\":\"1611328955384688643\",\"tableId\":\"1611328955321774082\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:48:55\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:02:43\",\"columnId\":\"1611328955384688644\",\"tableId\":\"1611328955321774082\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"L', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:02:43'); +INSERT INTO `sys_oper_log` VALUES (1611332442721972226, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_article\"}', '', 0, '', '2023-01-06 20:02:46'); +INSERT INTO `sys_oper_log` VALUES (1611334151103934466, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:08:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:09:33\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611332442470313984\",\"menuName\":\"文章列表\",\"orderNum\":1,\"path\":\"article\",\"component\":\"article/articleList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"system:article:list\",\"icon\":\"#\",\"remark\":\"文章列表菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:09:33'); +INSERT INTO `sys_oper_log` VALUES (1611335883103997953, '代码生成', 3, 'com.zhi.generator.controller.GenController.remove()', 'DELETE', 1, 'admin', '', '/tool/gen/1611328955321774082', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:16:26'); +INSERT INTO `sys_oper_log` VALUES (1611335898144772097, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_article\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:16:30'); +INSERT INTO `sys_oper_log` VALUES (1611336444532559873, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:18:40\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:18:40\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"capJavaField\":\"Id\",\"query\":false,\"increment\":true,\"required\":true,\"list\":true,\"pk\":true,\"edit\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:18:40\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"capJavaField\":\"UserId\",\"query\":true,\"increment\":false,\"required\":true,\"list\":true,\"pk\":false,\"edit\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:18:40\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:18:40'); +INSERT INTO `sys_oper_log` VALUES (1611336462454820866, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_article\"}', '', 0, '', '2023-01-06 20:18:44'); +INSERT INTO `sys_oper_log` VALUES (1611337350841962497, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313984', '127.0.0.1', '内网IP', '{}', '{\"code\":601,\"msg\":\"存在子菜单,不允许删除\",\"data\":null}', 0, '', '2023-01-06 20:22:16'); +INSERT INTO `sys_oper_log` VALUES (1611337368575479809, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313989', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:21'); +INSERT INTO `sys_oper_log` VALUES (1611337377375129601, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313988', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:23'); +INSERT INTO `sys_oper_log` VALUES (1611337397331628033, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313987', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:27'); +INSERT INTO `sys_oper_log` VALUES (1611337406869475329, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313986', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:30'); +INSERT INTO `sys_oper_log` VALUES (1611337416503791617, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313985', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:32'); +INSERT INTO `sys_oper_log` VALUES (1611337427971018754, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1611332442470313984', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:35'); +INSERT INTO `sys_oper_log` VALUES (1611337521889873922, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:21:38\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:22:57\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611336461808898048\",\"menuName\":\"文章列表\",\"orderNum\":1,\"path\":\"article\",\"component\":\"article/articleList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"article:article:list\",\"icon\":\"#\",\"remark\":\"文章列表菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:22:57'); +INSERT INTO `sys_oper_log` VALUES (1611338297752256513, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:21:38\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:26:01\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611336461808898048\",\"menuName\":\"文章列表\",\"orderNum\":1,\"path\":\"article\",\"component\":\"article/articleList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"article:article:list\",\"icon\":\"#\",\"remark\":\"文章列表菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:26:02'); +INSERT INTO `sys_oper_log` VALUES (1611341301511454722, '字典类型', 1, 'com.zhi.web.controller.system.SysDictTypeController.add()', 'POST', 1, 'admin', '', '/system/dict/type', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:37:58\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:37:58\",\"dictId\":\"1611341301444345857\",\"dictName\":\"文章状态\",\"dictType\":\"article_status\",\"status\":\"0\",\"remark\":\"文章状态\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:37:58'); +INSERT INTO `sys_oper_log` VALUES (1611341551689105411, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:38:57\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:38:57\",\"dictCode\":\"1611341551689105410\",\"dictSort\":0,\"dictLabel\":\"公开\",\"dictValue\":\"1\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"default\",\"isDefault\":null,\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:38:58'); +INSERT INTO `sys_oper_log` VALUES (1611341588632535041, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:39:06\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:39:06\",\"dictCode\":\"1611341588569620481\",\"dictSort\":0,\"dictLabel\":\"私密\",\"dictValue\":\"2\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"default\",\"isDefault\":null,\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:39:07'); +INSERT INTO `sys_oper_log` VALUES (1611341642575478786, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:39:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:39:19\",\"dictCode\":\"1611341642508369922\",\"dictSort\":0,\"dictLabel\":\"评论可见\",\"dictValue\":\"3\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"default\",\"isDefault\":null,\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:39:20'); +INSERT INTO `sys_oper_log` VALUES (1611342092091621378, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:52:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:41:06\",\"dictCode\":30,\"dictSort\":1,\"dictLabel\":\"原创\",\"dictValue\":\"1\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"success\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":\"原创\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:41:07'); +INSERT INTO `sys_oper_log` VALUES (1611342122953310209, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:52:56\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:41:14\",\"dictCode\":31,\"dictSort\":2,\"dictLabel\":\"转载\",\"dictValue\":\"2\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"info\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:41:14'); +INSERT INTO `sys_oper_log` VALUES (1611342160467165185, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:53:06\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:41:22\",\"dictCode\":32,\"dictSort\":3,\"dictLabel\":\"翻译\",\"dictValue\":\"3\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"warning\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:41:23'); +INSERT INTO `sys_oper_log` VALUES (1611342186727702530, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 19:52:56\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:41:29\",\"dictCode\":31,\"dictSort\":2,\"dictLabel\":\"转载\",\"dictValue\":\"2\",\"dictType\":\"article_type\",\"cssClass\":null,\"listClass\":\"danger\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:41:29'); +INSERT INTO `sys_oper_log` VALUES (1611342736844226562, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:43:40\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:43:40\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:43:40\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:43:40\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:43:40'); +INSERT INTO `sys_oper_log` VALUES (1611342967430283266, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:44:35\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:44:35\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:44:35\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:44:35\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:44:35'); +INSERT INTO `sys_oper_log` VALUES (1611343112708390914, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:45:10\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:45:10\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:45:10\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:45:10\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:45:10'); +INSERT INTO `sys_oper_log` VALUES (1611343352865849346, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:46:07\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:46:07\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:46:07\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:46:07\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:46:07'); +INSERT INTO `sys_oper_log` VALUES (1611345218471297025, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:53:32\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:53:32\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:53:32\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:53:32\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:53:32'); +INSERT INTO `sys_oper_log` VALUES (1611345544616181761, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:54:49\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:54:49\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:54:49\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"superColumn\":false,\"edit\":true,\"usableColumn\":false,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-06 20:54:49\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-06 20:54:50'); +INSERT INTO `sys_oper_log` VALUES (1611575763675504642, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_article', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:09:38'); +INSERT INTO `sys_oper_log` VALUES (1611576999736893442, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:14:33\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:14:33\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"pk\":true,\"insert\":false,\"increment\":true,\"capJavaField\":\"Id\",\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:14:33\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"pk\":false,\"insert\":true,\"increment\":false,\"capJavaField\":\"UserId\",\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:14:33\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:14:33'); +INSERT INTO `sys_oper_log` VALUES (1611577369401876482, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_article\"}', '', 0, '', '2023-01-07 12:16:01'); +INSERT INTO `sys_oper_log` VALUES (1611580812430508034, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1020,\"categoryId\":214,\"articleCover\":\"https://upload.linkstarted.top/articles/d01408d1fe1a2f9c5ab29f9503b25003.jpg\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:29:42'); +INSERT INTO `sys_oper_log` VALUES (1611584038554927105, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"sys_dept\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:42:31'); +INSERT INTO `sys_oper_log` VALUES (1611584400187817995, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"sys_config\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:43:57'); +INSERT INTO `sys_oper_log` VALUES (1611584546703245313, '代码生成', 3, 'com.zhi.generator.controller.GenController.remove()', 'DELETE', 1, 'admin', '', '/tool/gen/1611584400120709122', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:44:32'); +INSERT INTO `sys_oper_log` VALUES (1611584559487483906, '代码生成', 3, 'com.zhi.generator.controller.GenController.remove()', 'DELETE', 1, 'admin', '', '/tool/gen/1611584038424903681', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:44:35'); +INSERT INTO `sys_oper_log` VALUES (1611584710604062722, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:45:11\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611335897880530945\",\"tableName\":\"blog_article\",\"tableComment\":\"文章列表\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Article\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"article\",\"businessName\":\"article\",\"functionName\":\"文章列表\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:45:11\",\"columnId\":\"1611335898031525890\",\"tableId\":\"1611335897880530945\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:45:11\",\"columnId\":\"1611335898031525891\",\"tableId\":\"1611335897880530945\",\"columnName\":\"user_id\",\"columnComment\":\"作者\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:16:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:45:11\",\"columnId\":\"1611335898069274626\",\"tableId\":\"1611335897880530945\",\"columnName\":\"category_id\",\"columnComment\":\"文章分类\",\"columnType\":\"int(11)\",\"javaType\":\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:45:11'); +INSERT INTO `sys_oper_log` VALUES (1611585412994793473, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:38:58\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:47:58\",\"dictCode\":33,\"dictSort\":0,\"dictLabel\":\"公开\",\"dictValue\":\"1\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"primary\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:47:59'); +INSERT INTO `sys_oper_log` VALUES (1611585437833461761, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:38:58\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:48:04\",\"dictCode\":33,\"dictSort\":0,\"dictLabel\":\"公开\",\"dictValue\":\"1\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"success\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:48:05'); +INSERT INTO `sys_oper_log` VALUES (1611585457374724098, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:39:07\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:48:09\",\"dictCode\":34,\"dictSort\":0,\"dictLabel\":\"私密\",\"dictValue\":\"2\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"info\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:48:10'); +INSERT INTO `sys_oper_log` VALUES (1611585477427691522, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:39:07\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:48:14\",\"dictCode\":34,\"dictSort\":0,\"dictLabel\":\"私密\",\"dictValue\":\"2\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"warning\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:48:14'); +INSERT INTO `sys_oper_log` VALUES (1611585501221978113, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:39:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 12:48:19\",\"dictCode\":35,\"dictSort\":0,\"dictLabel\":\"评论可见\",\"dictValue\":\"3\",\"dictType\":\"article_status\",\"cssClass\":null,\"listClass\":\"primary\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 12:48:20'); +INSERT INTO `sys_oper_log` VALUES (1611611446146334727, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_category\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:31:26'); +INSERT INTO `sys_oper_log` VALUES (1611612756539179010, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:38\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":null},\"tableId\":\"1611611446079225858\",\"tableName\":\"blog_category\",\"tableComment\":\"分类管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Category\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.system\",\"moduleName\":\"category\",\"businessName\":\"category\",\"functionName\":\"分类管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:38\",\"columnId\":\"1611611446146334721\",\"tableId\":\"1611611446079225858\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:38\",\"columnId\":\"1611611446146334722\",\"tableId\":\"1611611446079225858\",\"columnName\":\"category_name\",\"columnComment\":\"分类名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"categoryName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"CategoryName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:38\",\"columnId\":\"1611611446146334723\",\"tableId\":\"1611611446079225858\",\"columnName\":\"create_time\",\"columnComment\":\"创建时间\",\"columnType\":\"datet', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:36:38'); +INSERT INTO `sys_oper_log` VALUES (1611612801036550145, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:48\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611611446079225858\",\"tableName\":\"blog_category\",\"tableComment\":\"分类管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Category\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.system\",\"moduleName\":\"category\",\"businessName\":\"category\",\"functionName\":\"分类管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:48\",\"columnId\":\"1611611446146334721\",\"tableId\":\"1611611446079225858\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:48\",\"columnId\":\"1611611446146334722\",\"tableId\":\"1611611446079225858\",\"columnName\":\"category_name\",\"columnComment\":\"分类名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"categoryName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"CategoryName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:36:48\",\"columnId\":\"1611611446146334723\",\"tableId\":\"1611611446079225858\",\"columnName\":\"create_time\",\"columnComment\":\"创建时间\",\"c', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:36:49'); +INSERT INTO `sys_oper_log` VALUES (1611613261961199618, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:38:38\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611611446079225858\",\"tableName\":\"blog_category\",\"tableComment\":\"分类管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Category\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.system\",\"moduleName\":\"category\",\"businessName\":\"category\",\"functionName\":\"分类管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:38:38\",\"columnId\":\"1611611446146334721\",\"tableId\":\"1611611446079225858\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:38:38\",\"columnId\":\"1611611446146334722\",\"tableId\":\"1611611446079225858\",\"columnName\":\"category_name\",\"columnComment\":\"分类名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"categoryName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"CategoryName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:38:38\",\"columnId\":\"1611611446146334723\",\"tableId\":\"1611611446079225858\",\"columnName\":\"create_time\",\"columnComment\":\"创建时间\",\"c', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:38:39'); +INSERT INTO `sys_oper_log` VALUES (1611613275215200258, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_category\"}', '', 0, '', '2023-01-07 14:38:42'); +INSERT INTO `sys_oper_log` VALUES (1611613712697884673, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:40:26\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611611446079225858\",\"tableName\":\"blog_category\",\"tableComment\":\"分类管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Category\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"category\",\"businessName\":\"category\",\"functionName\":\"分类管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:40:26\",\"columnId\":\"1611611446146334721\",\"tableId\":\"1611611446079225858\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"superColumn\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:40:26\",\"columnId\":\"1611611446146334722\",\"tableId\":\"1611611446079225858\",\"columnName\":\"category_name\",\"columnComment\":\"分类名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"categoryName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"CategoryName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:31:26\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:40:26\",\"columnId\":\"1611611446146334723\",\"tableId\":\"1611611446079225858\",\"columnName\":\"create_time\",\"columnComment\":\"创建时间\",\"col', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:40:26'); +INSERT INTO `sys_oper_log` VALUES (1611613727851905025, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_category\"}', '', 0, '', '2023-01-07 14:40:30'); +INSERT INTO `sys_oper_log` VALUES (1611615732909494273, '分类管理', 2, 'com.zhi.blog.controller.CategoryController.edit()', 'PUT', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":214,\"categoryName\":\"测试1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:48:28'); +INSERT INTO `sys_oper_log` VALUES (1611616146165878786, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:21:38\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:50:06\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611336461808898048\",\"menuName\":\"文章列表\",\"orderNum\":1,\"path\":\"article\",\"component\":\"article/articleList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"article:article:list\",\"icon\":\"list\",\"remark\":\"文章列表菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:50:06'); +INSERT INTO `sys_oper_log` VALUES (1611616243435982849, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:46:40\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-07 14:50:29\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611613727679938560\",\"menuName\":\"分类管理\",\"orderNum\":1,\"path\":\"category\",\"component\":\"category/category/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"category:category:list\",\"icon\":\"table\",\"remark\":\"分类管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-07 14:50:29'); +INSERT INTO `sys_oper_log` VALUES (1611975643208130562, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_tag\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 14:38:37'); +INSERT INTO `sys_oper_log` VALUES (1611975904022536193, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:39:39\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611975642985832449\",\"tableName\":\"blog_tag\",\"tableComment\":\"标签管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Tag\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"tag\",\"businessName\":\"tag\",\"functionName\":\"标签管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:38:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:39:39\",\"columnId\":\"1611975643027775489\",\"tableId\":\"1611975642985832449\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"usableColumn\":false,\"insert\":false,\"superColumn\":false,\"edit\":true,\"pk\":true,\"increment\":false,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:38:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:39:39\",\"columnId\":\"1611975643027775490\",\"tableId\":\"1611975642985832449\",\"columnName\":\"tag_name\",\"columnComment\":\"标签名\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"tagName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"usableColumn\":false,\"insert\":true,\"superColumn\":false,\"edit\":true,\"pk\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"TagName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:38:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:39:39\",\"columnId\":\"1611975643078107137\",\"tableId\":\"1611975642985832449\",\"columnName\":\"create_by\",\"columnComment\":\"\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"ja', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 14:39:39'); +INSERT INTO `sys_oper_log` VALUES (1611975929351938050, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_tag\"}', '', 0, '', '2023-01-08 14:39:45'); +INSERT INTO `sys_oper_log` VALUES (1611980941331382274, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_tag', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 14:59:40'); +INSERT INTO `sys_oper_log` VALUES (1611980984037785601, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:59:50\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1610972802922405889\"},\"tableId\":\"1611975642985832449\",\"tableName\":\"blog_tag\",\"tableComment\":\"标签管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Tag\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"tag\",\"businessName\":\"tag\",\"functionName\":\"标签管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:38:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:59:50\",\"columnId\":\"1611975643027775489\",\"tableId\":\"1611975642985832449\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"insert\":false,\"edit\":true,\"usableColumn\":false,\"superColumn\":false,\"query\":false,\"increment\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:38:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:59:50\",\"columnId\":\"1611975643027775490\",\"tableId\":\"1611975642985832449\",\"columnName\":\"tag_name\",\"columnComment\":\"标签名\",\"columnType\":\"varchar(11)\",\"javaType\":\"String\",\"javaField\":\"tagName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"insert\":true,\"edit\":true,\"usableColumn\":false,\"superColumn\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"TagName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:38:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 14:59:50\",\"columnId\":\"1611975643078107137\",\"tableId\":\"1611975642985832449\",\"columnName\":\"create_by\",\"columnComment\":\"\",\"columnType\":\"varchar(20)\",\"javaType\":\"Strin', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 14:59:50'); +INSERT INTO `sys_oper_log` VALUES (1611981482098786305, '标签管理', 2, 'com.zhi.blog.controller.TagController.edit()', 'PUT', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":54,\"tagName\":\"测试1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 15:01:49'); +INSERT INTO `sys_oper_log` VALUES (1611981497068257281, '标签管理', 2, 'com.zhi.blog.controller.TagController.edit()', 'PUT', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":54,\"tagName\":\"测试\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 15:01:53'); +INSERT INTO `sys_oper_log` VALUES (1611981706200449026, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:57:33\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 15:02:42\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611975928588574720\",\"menuName\":\"标签管理\",\"orderNum\":1,\"path\":\"tag\",\"component\":\"tag/tag/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"tag:tag:list\",\"icon\":\"icon\",\"remark\":\"标签管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 15:02:43'); +INSERT INTO `sys_oper_log` VALUES (1612007924555603969, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[Unable to execute HTTP request: Connect to 127.0.0.1:9000 [/127.0.0.1] failed: Connection refused: no further information]', '2023-01-08 16:46:54'); +INSERT INTO `sys_oper_log` VALUES (1612008091446960129, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":3,\"configKey\":\"aliyun\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:47:33'); +INSERT INTO `sys_oper_log` VALUES (1612008140490956802, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[The OSS Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 63BA83305423BA303718605A; S3 Extended Request ID: ruoyi.oss-cn-beijing.aliyuncs.com; Proxy: null)]', '2023-01-08 16:47:45'); +INSERT INTO `sys_oper_log` VALUES (1612008176973012994, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[The OSS Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 63BA8339A645AE3338D94669; S3 Extended Request ID: ruoyi.oss-cn-beijing.aliyuncs.com; Proxy: null)]', '2023-01-08 16:47:54'); +INSERT INTO `sys_oper_log` VALUES (1612008327686938626, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":4,\"configKey\":\"qcloud\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:48:30'); +INSERT INTO `sys_oper_log` VALUES (1612008998649749505, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":3,\"configKey\":\"aliyun\",\"accessKey\":\" LTAI5tAaC4gFYq1qRjSj1y5E\",\"secretKey\":\" oJf6qB2y9byKdnVLsyBJUblJ2qVVLt\",\"bucketName\":\"2831826106\",\"prefix\":\"\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"1\",\"region\":\"\",\"ext1\":\"\",\"remark\":null,\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:51:10'); +INSERT INTO `sys_oper_log` VALUES (1612009015703789569, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":3,\"configKey\":\"aliyun\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:51:14'); +INSERT INTO `sys_oper_log` VALUES (1612009218578079745, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":3,\"configKey\":\"aliyun\",\"accessKey\":\" LTAI5tAaC4gFYq1qRjSj1y5E\",\"secretKey\":\" oJf6qB2y9byKdnVLsyBJUblJ2qVVLt\",\"bucketName\":\"2831826106\",\"prefix\":\"\",\"endpoint\":\"oss-cn-beijing.aliyuncs.com\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"0\",\"region\":\"\",\"ext1\":\"\",\"remark\":\"\",\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:52:02'); +INSERT INTO `sys_oper_log` VALUES (1612009288484544514, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612009288484544513\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/b5d43d06c1be409d9174efa1dcf30c4d.jpg\",\"fileName\":\"b.jpg\"}}', 0, '', '2023-01-08 16:52:19'); +INSERT INTO `sys_oper_log` VALUES (1612009297372274690, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:52:21'); +INSERT INTO `sys_oper_log` VALUES (1612010993678835714, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612010993611726850\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/e4aebcf8cc864490baf9dcb669b16b5e.jpg\",\"fileName\":\"hos.jpg\"}}', 0, '', '2023-01-08 16:59:05'); +INSERT INTO `sys_oper_log` VALUES (1612011001102753793, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612010993611726850\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 16:59:07'); +INSERT INTO `sys_oper_log` VALUES (1612013656831188994, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612010993611726850', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:09:40'); +INSERT INTO `sys_oper_log` VALUES (1612013716100898818, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612013716100898817\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/7a09c2d03aa14ca48308379828d3f6e8.jpg\",\"fileName\":\"b.jpg\"}}', 0, '', '2023-01-08 17:09:54'); +INSERT INTO `sys_oper_log` VALUES (1612014136152055810, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612013716100898817\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:11:34'); +INSERT INTO `sys_oper_log` VALUES (1612014934458130433, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612013716100898817', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:14:45'); +INSERT INTO `sys_oper_log` VALUES (1612014983883808770, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612014983883808769\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/3a3488ceb5e24ef78e2283d976cfc5ab.jpg\",\"fileName\":\"【4K】马尔代夫日落3840x2160风景壁纸_彼岸图网.jpg\"}}', 0, '', '2023-01-08 17:14:57'); +INSERT INTO `sys_oper_log` VALUES (1612015015211065346, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612014983883808769\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:15:04'); +INSERT INTO `sys_oper_log` VALUES (1612015220677435393, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612014983883808769', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:15:53'); +INSERT INTO `sys_oper_log` VALUES (1612015247776833538, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612015247718113282\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/acfb70172d404da4a16e2fb02811363c.jpg\",\"fileName\":\"b.jpg\"}}', 0, '', '2023-01-08 17:16:00'); +INSERT INTO `sys_oper_log` VALUES (1612015254584188929, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612015247718113282\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:16:01'); +INSERT INTO `sys_oper_log` VALUES (1612015364521091074, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612015247718113282', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:16:27'); +INSERT INTO `sys_oper_log` VALUES (1612015427624394754, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612015427624394753\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/5acccb368dbe40e5b7fc4cee2f788048.jpg\",\"fileName\":\"QQ图片20210424191210.jpg\"}}', 0, '', '2023-01-08 17:16:42'); +INSERT INTO `sys_oper_log` VALUES (1612015439607521281, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612015427624394753\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:16:45'); +INSERT INTO `sys_oper_log` VALUES (1612015792923107329, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612015427624394753', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:18:10'); +INSERT INTO `sys_oper_log` VALUES (1612015820236414978, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612015820169306114\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/d494400f449045e49251ae78113ac802.jpg\",\"fileName\":\"grey-heron-5370732.jpg\"}}', 0, '', '2023-01-08 17:18:16'); +INSERT INTO `sys_oper_log` VALUES (1612015828583079938, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612015820169306114\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":2,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:18:18'); +INSERT INTO `sys_oper_log` VALUES (1612016821118984193, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612015820169306114\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:22:15'); +INSERT INTO `sys_oper_log` VALUES (1612019525245493249, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612019525182578690\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/ed00d10800f0447182092eafe911620c.jpg\",\"fileName\":\"b.jpg\"}}', 0, '', '2023-01-08 17:32:59'); +INSERT INTO `sys_oper_log` VALUES (1612019544329576449, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612019525182578690', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:33:04'); +INSERT INTO `sys_oper_log` VALUES (1612019947783872513, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612015820169306114', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:34:40'); +INSERT INTO `sys_oper_log` VALUES (1612020086342705154, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612019985264173058\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/ba512aa4942046338fae39a3e33e6702.jpg\",\"fileName\":\"diagoona-bg-3.jpg\"}}', 0, '', '2023-01-08 17:35:13'); +INSERT INTO `sys_oper_log` VALUES (1612020180232200194, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612019985264173058', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 17:35:36'); +INSERT INTO `sys_oper_log` VALUES (1612020205838426115, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612020205838426114\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/809c0a315f9f41a98a0046aea45d437b.jpg\",\"fileName\":\"diagoona-bg-21.jpg\"}}', 0, '', '2023-01-08 17:35:42'); +INSERT INTO `sys_oper_log` VALUES (1612030689757147138, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612030689601957890\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/08/3eef4a5464cc472e98c3f0f7622bf721.jpg\",\"fileName\":\"hos.jpg\"}}', 0, '', '2023-01-08 18:17:21'); +INSERT INTO `sys_oper_log` VALUES (1612031271494545409, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"2022-12-02\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 18:19:40'); +INSERT INTO `sys_oper_log` VALUES (1612038602492035073, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 18:48:48'); +INSERT INTO `sys_oper_log` VALUES (1612038674080415746, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 18:49:05'); +INSERT INTO `sys_oper_log` VALUES (1612038692724097026, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '', 1, '不允许重复提交,请稍候再试', '2023-01-08 18:49:09'); +INSERT INTO `sys_oper_log` VALUES (1612038704522674177, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 18:49:12'); +INSERT INTO `sys_oper_log` VALUES (1612040317941399554, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 18:55:37'); +INSERT INTO `sys_oper_log` VALUES (1612040455162249217, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryName\":\"正式\"}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( id, category_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-08 18:56:09'); +INSERT INTO `sys_oper_log` VALUES (1612040578810331139, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryName\":\"正式\"}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( id, category_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-08 18:56:39'); +INSERT INTO `sys_oper_log` VALUES (1612040823984177154, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryName\":\"正式\"}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( id, category_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-08 18:57:37'); +INSERT INTO `sys_oper_log` VALUES (1612041146849116162, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryName\":\"正式\"}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( id, category_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-08 18:58:54'); +INSERT INTO `sys_oper_log` VALUES (1612041197772161027, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryName\":\"正式\"}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( id, category_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-08 18:59:06'); +INSERT INTO `sys_oper_log` VALUES (1612041845909594114, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":215,\"categoryName\":\"正式\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 19:01:41'); +INSERT INTO `sys_oper_log` VALUES (1612041926402482178, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/215', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 19:02:00'); +INSERT INTO `sys_oper_log` VALUES (1612041985789632513, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":216,\"categoryName\":\"springboot\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 19:02:14'); +INSERT INTO `sys_oper_log` VALUES (1612063439776227330, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":216,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 20:27:29'); +INSERT INTO `sys_oper_log` VALUES (1612063816231788545, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":217,\"categoryName\":\"mybatis\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 20:28:59'); +INSERT INTO `sys_oper_log` VALUES (1612067010504663042, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":216,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 20:41:41'); +INSERT INTO `sys_oper_log` VALUES (1612069008167772162, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":216,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 20:49:37'); +INSERT INTO `sys_oper_log` VALUES (1612071313596305409, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":216,\"categoryName\":\"mybatis\",\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 20:58:47'); +INSERT INTO `sys_oper_log` VALUES (1612072507148357633, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"mybatis\",\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 21:03:31'); +INSERT INTO `sys_oper_log` VALUES (1612072577054822401, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":null,\"categoryName\":\"666\",\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 21:03:48'); +INSERT INTO `sys_oper_log` VALUES (1612076693399347201, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"vue\",\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'create_time\' doesn\'t have a default value\r\n### The error may exist in file [G:\\桌面\\ftz-blog\\zhi-blog\\zhi-myblog\\target\\classes\\mapper\\category\\CategoryMapper.xml]\r\n### The error may involve defaultParameterMap\r\n### The error occurred while setting parameters\r\n### SQL: insert into blog_category (category_name) values (?)\r\n### Cause: java.sql.SQLException: Field \'create_time\' doesn\'t have a default value\n; Field \'create_time\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'create_time\' doesn\'t have a default value', '2023-01-08 21:20:09'); +INSERT INTO `sys_oper_log` VALUES (1612077627307302913, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":218,\"categoryName\":\"vue\",\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 21:23:52'); +INSERT INTO `sys_oper_log` VALUES (1612095929475768321, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":216,\"categoryName\":\"springboot\",\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 22:36:36'); +INSERT INTO `sys_oper_log` VALUES (1612096014162960385, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"springboot\",\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-08 22:36:56'); +INSERT INTO `sys_oper_log` VALUES (1612283779408273410, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612283779278249985\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/09/2362e4e2d41b48218817a761fff30633.jpg\",\"fileName\":\"【4K】马尔代夫日落3840x2160风景壁纸_彼岸图网.jpg\"}}', 0, '', '2023-01-09 11:03:02'); +INSERT INTO `sys_oper_log` VALUES (1612289916572606465, '分类管理', 2, 'com.zhi.blog.controller.CategoryController.edit()', 'PUT', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":216,\"categoryName\":\"正式\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 11:27:26'); +INSERT INTO `sys_oper_log` VALUES (1612290027352563714, '分类管理', 2, 'com.zhi.blog.controller.CategoryController.edit()', 'PUT', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":217,\"categoryName\":\"付费\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 11:27:52'); +INSERT INTO `sys_oper_log` VALUES (1612290049561403394, '分类管理', 2, 'com.zhi.blog.controller.CategoryController.edit()', 'PUT', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":218,\"categoryName\":\"积分\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 11:27:57'); +INSERT INTO `sys_oper_log` VALUES (1612293804071657473, '标签管理', 1, 'com.zhi.blog.controller.TagController.add()', 'POST', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"tagName\":\"vue\"}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/TagMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TagMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_tag ( id, tag_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-09 11:42:53'); +INSERT INTO `sys_oper_log` VALUES (1612294117579087873, '标签管理', 1, 'com.zhi.blog.controller.TagController.add()', 'POST', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"tagName\":\"vue\"}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TagMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TagMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_tag ( tag_name, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'id\' doesn\'t have a default value\n; Field \'id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'id\' doesn\'t have a default value', '2023-01-09 11:44:07'); +INSERT INTO `sys_oper_log` VALUES (1612294279378558977, '标签管理', 1, 'com.zhi.blog.controller.TagController.add()', 'POST', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":55,\"tagName\":\"vue\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 11:44:46'); +INSERT INTO `sys_oper_log` VALUES (1612294315587985410, '标签管理', 1, 'com.zhi.blog.controller.TagController.add()', 'POST', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":56,\"tagName\":\"springboot\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 11:44:54'); +INSERT INTO `sys_oper_log` VALUES (1612294341974351873, '标签管理', 1, 'com.zhi.blog.controller.TagController.add()', 'POST', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":57,\"tagName\":\"mybatis\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 11:45:01'); +INSERT INTO `sys_oper_log` VALUES (1612344316095709185, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tag\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-08 15:01:53\",\"id\":54,\"tagName\":\"测试\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-09 11:44:46\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-09 11:44:46\",\"id\":55,\"tagName\":\"vue\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-09 11:44:54\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-09 11:44:54\",\"id\":56,\"tagName\":\"springboot\"}],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 15:03:36'); +INSERT INTO `sys_oper_log` VALUES (1612420656517939202, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagName\":null,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 20:06:57'); +INSERT INTO `sys_oper_log` VALUES (1612421604418060290, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagName\":null,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 20:10:42'); +INSERT INTO `sys_oper_log` VALUES (1612422019184394241, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagName\":null,\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 20:12:21'); +INSERT INTO `sys_oper_log` VALUES (1612422245802700801, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"888\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 20:13:15'); +INSERT INTO `sys_oper_log` VALUES (1612430337000947714, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"vue\",\"mybatis\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select id from blog_tag b where b.tag_name = ?}\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select id from blog_tag b where b.tag_name = ?}', '2023-01-09 20:45:25'); +INSERT INTO `sys_oper_log` VALUES (1612431005149380609, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"vue\",\"mybatis\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select id from blog_tag b where b.tag_name = ?}\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select id from blog_tag b where b.tag_name = ?}', '2023-01-09 20:48:04'); +INSERT INTO `sys_oper_log` VALUES (1612431169213714433, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"vue\",\"mybatis\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '', 1, 'nested exception is org.apache.ibatis.binding.BindingException: Parameter \'aid\' not found. Available parameters are [arg1, arg0, param1, param2]', '2023-01-09 20:48:43'); +INSERT INTO `sys_oper_log` VALUES (1612431394842128385, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"vue\",\"mybatis\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '', 1, 'nested exception is org.apache.ibatis.binding.BindingException: Parameter \'aid\' not found. Available parameters are [arg1, arg0, param1, param2]', '2023-01-09 20:49:37'); +INSERT INTO `sys_oper_log` VALUES (1612431672647659521, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"vue\",\"mybatis\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '', 1, 'nested exception is org.apache.ibatis.binding.BindingException: Parameter \'aid\' not found. Available parameters are [arg1, arg0, param1, param2]', '2023-01-09 20:50:43'); +INSERT INTO `sys_oper_log` VALUES (1612433223332192258, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"vue\",\"mybatis\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 20:56:53'); +INSERT INTO `sys_oper_log` VALUES (1612435826787020801, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"springboot\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:07:13'); +INSERT INTO `sys_oper_log` VALUES (1612435903685390338, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"springboot\",\"66\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:07:32'); +INSERT INTO `sys_oper_log` VALUES (1612437422572851202, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:13:34'); +INSERT INTO `sys_oper_log` VALUES (1612437522720247809, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":1,\"viewsCount\":8}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:13:58'); +INSERT INTO `sys_oper_log` VALUES (1612447695627112450, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"付费\",\"tagNameList\":[\"测试\",\"vue\",\"springboot\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:54:23'); +INSERT INTO `sys_oper_log` VALUES (1612447779588689922, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":219,\"categoryName\":\"爸爸\",\"tagNameList\":[\"测试\",\"vue\",\"springboot\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:54:43'); +INSERT INTO `sys_oper_log` VALUES (1612447948573003777, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\",\"vue\",\"springboot\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:55:23'); +INSERT INTO `sys_oper_log` VALUES (1612448008983564290, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:55:38'); +INSERT INTO `sys_oper_log` VALUES (1612448481962643457, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/219', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 21:57:31'); +INSERT INTO `sys_oper_log` VALUES (1612468977341059073, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-06 20:21:38\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-09 23:18:57\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611336461808898048\",\"menuName\":\"文章列表\",\"orderNum\":2,\"path\":\"article\",\"component\":\"article/articleList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"article:article:list\",\"icon\":\"list\",\"remark\":\"文章列表菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 23:18:57'); +INSERT INTO `sys_oper_log` VALUES (1612469013948944385, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-07 14:46:40\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-09 23:19:05\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611613727679938560\",\"menuName\":\"分类管理\",\"orderNum\":3,\"path\":\"category\",\"component\":\"category/category/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"category:category:list\",\"icon\":\"table\",\"remark\":\"分类管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 23:19:06'); +INSERT INTO `sys_oper_log` VALUES (1612469037697093634, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-08 14:57:33\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-09 23:19:11\",\"parentName\":null,\"parentId\":\"1610972802922405889\",\"children\":[],\"menuId\":\"1611975928588574720\",\"menuName\":\"标签管理\",\"orderNum\":4,\"path\":\"tag\",\"component\":\"tag/tag/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"tag:tag:list\",\"icon\":\"icon\",\"remark\":\"标签管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-09 23:19:11'); +INSERT INTO `sys_oper_log` VALUES (1612686933299888129, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 13:45:02'); +INSERT INTO `sys_oper_log` VALUES (1612687071468650498, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"部署成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 13:45:35'); +INSERT INTO `sys_oper_log` VALUES (1612691681054883841, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":1,\"originalUrl\":\"1\",\"isTop\":0,\"isDelete\":0,\"status\":1,\"likeCount\":0,\"viewsCount\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 14:03:54'); +INSERT INTO `sys_oper_log` VALUES (1612695678658609154, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612695678591500290\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/7e831194ef4a4973b9c2de4ea2252a22.jpg\",\"fileName\":\"QQ图片20210424191204.jpg\"}}', 0, '', '2023-01-10 14:19:47'); +INSERT INTO `sys_oper_log` VALUES (1612695952194338817, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612695952131424258\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/374080dfc43c447a885c39285d0436f0.jpg\",\"fileName\":\"少女 樱花 屋子 4k动漫壁纸_彼岸图网.jpg\"}}', 0, '', '2023-01-10 14:20:52'); +INSERT INTO `sys_oper_log` VALUES (1612696685740359682, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612696685677445121\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/79162c525f064ec2b014fd628439ff83.jpg\",\"fileName\":\"b.jpg\"}}', 0, '', '2023-01-10 14:23:47'); +INSERT INTO `sys_oper_log` VALUES (1612699455767781378, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612696685677445121\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 14:34:47'); +INSERT INTO `sys_oper_log` VALUES (1612699959658881025, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612696685677445121\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 14:36:48'); +INSERT INTO `sys_oper_log` VALUES (1612702970615508993, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612696685677445121\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-01-10 14:48:45'); +INSERT INTO `sys_oper_log` VALUES (1612703410769965058, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612696685677445121\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-01-10 14:50:30'); +INSERT INTO `sys_oper_log` VALUES (1612703601988251650, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612696685677445121\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-01-10 14:51:16'); +INSERT INTO `sys_oper_log` VALUES (1612704198657400833, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612696685677445121\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'class java.lang.String cannot be cast to class java.lang.Long (java.lang.String and java.lang.Long are in module java.base of loader \'bootstrap\')', '2023-01-10 14:53:38'); +INSERT INTO `sys_oper_log` VALUES (1612705924198240257, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612705924017885186\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/ea3a501330294556a2e0155759798c80.jpg\",\"fileName\":\"QQ图片20210424183800.jpg\"}}', 0, '', '2023-01-10 15:00:30'); +INSERT INTO `sys_oper_log` VALUES (1612705954372063233, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:00:37'); +INSERT INTO `sys_oper_log` VALUES (1612706398364307457, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-01-10 15:02:23'); +INSERT INTO `sys_oper_log` VALUES (1612707381672755202, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:06:17'); +INSERT INTO `sys_oper_log` VALUES (1612707569581768706, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:07:02'); +INSERT INTO `sys_oper_log` VALUES (1612707630663417857, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:07:16'); +INSERT INTO `sys_oper_log` VALUES (1612707825014886401, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:08:03'); +INSERT INTO `sys_oper_log` VALUES (1612707959668822018, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:08:35'); +INSERT INTO `sys_oper_log` VALUES (1612708397495480321, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:10:19'); +INSERT INTO `sys_oper_log` VALUES (1612708512935309314, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612705924017885186\",\"articleTitle\":\"新增测试\",\"articleContent\":\"新增测试666\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:10:47'); +INSERT INTO `sys_oper_log` VALUES (1612710518190047234, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612710517921611777\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/ad1f6ae51b984e529863a1916b784b0f.jpg\",\"fileName\":\"QQ图片20210424183800.jpg\"}}', 0, '', '2023-01-10 15:18:45'); +INSERT INTO `sys_oper_log` VALUES (1612710537555148802, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710517921611777\",\"articleTitle\":\"新增测试1\",\"articleContent\":\"新增测试文章\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:18:50'); +INSERT INTO `sys_oper_log` VALUES (1612710618089979906, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710517921611777\",\"articleTitle\":\"新增测试1\",\"articleContent\":\"新增测试文章\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:19:09'); +INSERT INTO `sys_oper_log` VALUES (1612710664487370754, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710517921611777\",\"articleTitle\":\"新增测试1\",\"articleContent\":\"新增测试文章\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:19:20'); +INSERT INTO `sys_oper_log` VALUES (1612710956725501954, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612710956658393089\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/6c9410da771e41fc8fa273ec581f6c30.jpg\",\"fileName\":\"QQ图片20210424183800.jpg\"}}', 0, '', '2023-01-10 15:20:29'); +INSERT INTO `sys_oper_log` VALUES (1612710968616353794, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:20:32'); +INSERT INTO `sys_oper_log` VALUES (1612711228587704322, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:21:34'); +INSERT INTO `sys_oper_log` VALUES (1612711355960328194, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:22:05'); +INSERT INTO `sys_oper_log` VALUES (1612711586546393090, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article ( category_id, article_cover, article_title, article_content, type, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-10 15:23:00'); +INSERT INTO `sys_oper_log` VALUES (1612711780662910977, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":140,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 15:23:46'); +INSERT INTO `sys_oper_log` VALUES (1612711926775685122, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":140,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 15:24:21'); +INSERT INTO `sys_oper_log` VALUES (1612719243856457730, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\",\"springboot\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 15:53:25'); +INSERT INTO `sys_oper_log` VALUES (1612719310415867906, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 15:53:41'); +INSERT INTO `sys_oper_log` VALUES (1612719497125310466, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612719497062395905\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/97c978766c91400ea22d493e5f70f73f.jpg\",\"fileName\":\"QQ图片20210424183727.jpg\"}}', 0, '', '2023-01-10 15:54:26'); +INSERT INTO `sys_oper_log` VALUES (1612719512015089666, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的\",\"tagNameList\":[\"新的\"],\"articleCover\":\"1612719497062395905\",\"articleTitle\":\"新的新增测试\",\"articleContent\":\"新的新增测试啦啦啦\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 15:54:29'); +INSERT INTO `sys_oper_log` VALUES (1612720191672692737, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的\",\"tagNameList\":[\"新的\"],\"articleCover\":\"1612719497062395905\",\"articleTitle\":\"新的新增测试\",\"articleContent\":\"新的新增测试啦啦啦\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 15:57:11'); +INSERT INTO `sys_oper_log` VALUES (1612720564932194305, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的\",\"tagNameList\":[\"新的\"],\"articleCover\":\"1612719497062395905\",\"articleTitle\":\"新的新增测试\",\"articleContent\":\"新的新增测试啦啦啦\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 15:58:40'); +INSERT INTO `sys_oper_log` VALUES (1612720748084867074, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的\",\"tagNameList\":[\"新的\"],\"articleCover\":\"1612719497062395905\",\"articleTitle\":\"新的新增测试\",\"articleContent\":\"新的新增测试啦啦啦\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 15:59:24'); +INSERT INTO `sys_oper_log` VALUES (1612721222217379842, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的\",\"tagNameList\":[\"新的\"],\"articleCover\":\"1612719497062395905\",\"articleTitle\":\"新的新增测试\",\"articleContent\":\"新的新增测试啦啦啦\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 16:01:17'); +INSERT INTO `sys_oper_log` VALUES (1612721915804266497, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":220,\"categoryName\":\"新的\",\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:04:02'); +INSERT INTO `sys_oper_log` VALUES (1612722381791440897, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/220', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:05:53'); +INSERT INTO `sys_oper_log` VALUES (1612722453367238657, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":220,\"categoryName\":null,\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-01-10 16:06:10'); +INSERT INTO `sys_oper_log` VALUES (1612722628269715457, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":220,\"categoryName\":null,\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-01-10 16:06:52'); +INSERT INTO `sys_oper_log` VALUES (1612722794951356418, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:07:32'); +INSERT INTO `sys_oper_log` VALUES (1612722967383388162, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":221,\"categoryName\":\"新的\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:08:13'); +INSERT INTO `sys_oper_log` VALUES (1612723014258929666, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":221,\"categoryName\":\"新的\",\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:08:24'); +INSERT INTO `sys_oper_log` VALUES (1612723053760884738, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/221', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:08:34'); +INSERT INTO `sys_oper_log` VALUES (1612723376348999681, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/60', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:09:51'); +INSERT INTO `sys_oper_log` VALUES (1612724795189768193, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/58', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:15:29'); +INSERT INTO `sys_oper_log` VALUES (1612729012243722241, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/59', '127.0.0.1', '内网IP', '{}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )', '2023-01-10 16:32:14'); +INSERT INTO `sys_oper_log` VALUES (1612729228552368130, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/59', '127.0.0.1', '内网IP', '{}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )', '2023-01-10 16:33:06'); +INSERT INTO `sys_oper_log` VALUES (1612729419275759617, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/59', '127.0.0.1', '内网IP', '{}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )', '2023-01-10 16:33:51'); +INSERT INTO `sys_oper_log` VALUES (1612729637027246081, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/59', '127.0.0.1', '内网IP', '{}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error querying database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: select count(*) from blog_article_tag where tag_id = ? )', '2023-01-10 16:34:43'); +INSERT INTO `sys_oper_log` VALUES (1612729889964736514, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/59', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"请先修改与该标签对应的文章\",\"data\":null}', 0, '', '2023-01-10 16:35:43'); +INSERT INTO `sys_oper_log` VALUES (1612730289178570754, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/59', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应该标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 16:37:19'); +INSERT INTO `sys_oper_log` VALUES (1612730430824411137, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/57', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:37:52'); +INSERT INTO `sys_oper_log` VALUES (1612730777135509506, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1612030689601957890\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:39:15'); +INSERT INTO `sys_oper_log` VALUES (1612731173878919170, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:40:50'); +INSERT INTO `sys_oper_log` VALUES (1612731416804618241, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":222,\"categoryName\":\"新的\",\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:41:48'); +INSERT INTO `sys_oper_log` VALUES (1612731565245231106, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/61', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应该标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 16:42:23'); +INSERT INTO `sys_oper_log` VALUES (1612731587626037250, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/61', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应该标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 16:42:28'); +INSERT INTO `sys_oper_log` VALUES (1612731709780946945, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/61', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应该标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 16:42:57'); +INSERT INTO `sys_oper_log` VALUES (1612731830732091393, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/222', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:43:26'); +INSERT INTO `sys_oper_log` VALUES (1612731863913230338, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:43:34'); +INSERT INTO `sys_oper_log` VALUES (1612731906019848193, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:43:44'); +INSERT INTO `sys_oper_log` VALUES (1612731938768973826, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/61', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:43:52'); +INSERT INTO `sys_oper_log` VALUES (1612732987181395969, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612732987122675713\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/411d45bd7c324201a2a5d543491c5f77.jpg\",\"fileName\":\"hos.jpg\"}}', 0, '', '2023-01-10 16:48:02'); +INSERT INTO `sys_oper_log` VALUES (1612733000938713089, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的测试\",\"tagNameList\":[\"新的测试\"],\"articleCover\":\"1612732987122675713\",\"articleTitle\":\"新的测试\",\"articleContent\":\"## 新的测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 16:48:05'); +INSERT INTO `sys_oper_log` VALUES (1612734226174603266, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":\"新的测试\",\"tagNameList\":[\"新的测试\"],\"articleCover\":\"1612732987122675713\",\"articleTitle\":\"新的测试\",\"articleContent\":\"## 新的测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\r\n### The error may exist in com/zhi/blog/mapper/ArticleMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.ArticleMapper.insertById-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_article_tag(article_id,tag_id) VALUES(?,?)\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null\n; Column \'article_id\' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column \'article_id\' cannot be null', '2023-01-10 16:52:57'); +INSERT INTO `sys_oper_log` VALUES (1612734550901813249, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\",\"新的\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:54:15'); +INSERT INTO `sys_oper_log` VALUES (1612734600759504897, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/63', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应该标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 16:54:27'); +INSERT INTO `sys_oper_log` VALUES (1612734641393922050, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:54:36'); +INSERT INTO `sys_oper_log` VALUES (1612734676005318657, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/63', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 16:54:45'); +INSERT INTO `sys_oper_log` VALUES (1612740241414733826, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":223,\"categoryName\":\"新的测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:16:51'); +INSERT INTO `sys_oper_log` VALUES (1612740262306562049, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/223', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:16:56'); +INSERT INTO `sys_oper_log` VALUES (1612740294661423105, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章666\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:17:04'); +INSERT INTO `sys_oper_log` VALUES (1612740319223267329, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/62', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:17:10'); +INSERT INTO `sys_oper_log` VALUES (1612740474215383042, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612740474085359618\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/9487a03afd7647949633c8be9b8bca28.jpg\",\"fileName\":\"QQ图片20210424183800.jpg\"}}', 0, '', '2023-01-10 17:17:47'); +INSERT INTO `sys_oper_log` VALUES (1612740486726991873, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":141,\"userId\":1,\"categoryId\":224,\"categoryName\":\"最后测试\",\"tagNameList\":[\"最后测试\"],\"articleCover\":\"1612740474085359618\",\"articleTitle\":\"最后的测试\",\"articleContent\":\"最后的测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:17:50'); +INSERT INTO `sys_oper_log` VALUES (1612740611645947906, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/141', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:18:20'); +INSERT INTO `sys_oper_log` VALUES (1612740643283582977, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/224', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:18:27'); +INSERT INTO `sys_oper_log` VALUES (1612740659750420482, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/64', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应此标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 17:18:31'); +INSERT INTO `sys_oper_log` VALUES (1612740799412355073, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/64', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应此标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 17:19:05'); +INSERT INTO `sys_oper_log` VALUES (1612740953850822657, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/64', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:19:41'); +INSERT INTO `sys_oper_log` VALUES (1612741710532702210, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":140,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"html\",\"最终测试\"],\"articleCover\":\"1612710956658393089\",\"articleTitle\":\"新增测试文章\",\"articleContent\":\"测试文章新增\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:22:42'); +INSERT INTO `sys_oper_log` VALUES (1612741739200770049, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/65', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应此标签,无法删除\",\"data\":null}', 0, '', '2023-01-10 17:22:49'); +INSERT INTO `sys_oper_log` VALUES (1612741772428046338, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/140', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:22:56'); +INSERT INTO `sys_oper_log` VALUES (1612741788207017985, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/65', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:23:00'); +INSERT INTO `sys_oper_log` VALUES (1612742639868833794, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612009288484544513\",\"articleTitle\":\"测试文章\",\"articleContent\":\"这一次我一定要成功\",\"type\":2,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:26:23'); +INSERT INTO `sys_oper_log` VALUES (1612742812690935809, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612742812628021250\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/a4e7cd098c6d4afa8ded437288ce8c22.jpg\",\"fileName\":\"QQ图片20210424183800.jpg\"}}', 0, '', '2023-01-10 17:27:05'); +INSERT INTO `sys_oper_log` VALUES (1612742826859294721, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":142,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"测试\"],\"articleCover\":\"1612742812628021250\",\"articleTitle\":\"NEW\",\"articleContent\":\"NEW\",\"type\":3,\"originalUrl\":null,\"isDelete\":0,\"status\":2}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:27:08'); +INSERT INTO `sys_oper_log` VALUES (1612742859516145665, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/142', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 17:27:16'); +INSERT INTO `sys_oper_log` VALUES (1612748733320130562, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612748733253021697\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/3acf65d19bcd4fa18ec3847f3d0c90be.jpg\",\"fileName\":\"b.jpg\"}}', 0, '', '2023-01-10 17:50:36'); +INSERT INTO `sys_oper_log` VALUES (1612756503863881730, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 20:13:41\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 18:21:28\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1610972802922405889\",\"menuName\":\"文章管理\",\"orderNum\":1,\"path\":\"article\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"education\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 18:21:29'); +INSERT INTO `sys_oper_log` VALUES (1612756556611448834, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 18:21:41\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":1,\"menuName\":\"系统管理\",\"orderNum\":2,\"path\":\"system\",\"component\":null,\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"\",\"icon\":\"system\",\"remark\":\"系统管理目录\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 18:21:41'); +INSERT INTO `sys_oper_log` VALUES (1612780988134453250, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612710956658393089', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:58:46'); +INSERT INTO `sys_oper_log` VALUES (1612781012268478465, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612719497062395905', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:58:52'); +INSERT INTO `sys_oper_log` VALUES (1612781023395966977, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612732987122675713', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:58:55'); +INSERT INTO `sys_oper_log` VALUES (1612781042282917890, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612009288484544513', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:58:59'); +INSERT INTO `sys_oper_log` VALUES (1612781051376168961, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612020205838426114', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:01'); +INSERT INTO `sys_oper_log` VALUES (1612781061702545410, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612030689601957890', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:04'); +INSERT INTO `sys_oper_log` VALUES (1612781068602175490, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612283779278249985', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:05'); +INSERT INTO `sys_oper_log` VALUES (1612781075120123906, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612695678591500290', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:07'); +INSERT INTO `sys_oper_log` VALUES (1612781080820183041, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612695952131424258', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:08'); +INSERT INTO `sys_oper_log` VALUES (1612781088097300481, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612696685677445121', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:10'); +INSERT INTO `sys_oper_log` VALUES (1612781095118565377, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612705924017885186', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:12'); +INSERT INTO `sys_oper_log` VALUES (1612781101837840386, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612710517921611777', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:13'); +INSERT INTO `sys_oper_log` VALUES (1612781109261758466, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612740474085359618', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:15'); +INSERT INTO `sys_oper_log` VALUES (1612781118828965889, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612742812628021250', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:17'); +INSERT INTO `sys_oper_log` VALUES (1612781129033707521, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612748733253021697', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 19:59:20'); +INSERT INTO `sys_oper_log` VALUES (1612781294230564865, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612009288484544513', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"操作失败\",\"data\":null}', 0, '', '2023-01-10 19:59:59'); +INSERT INTO `sys_oper_log` VALUES (1612781375247740930, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612781375180632066\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"fileName\":\"QQ图片20210424191151.jpg\"}}', 0, '', '2023-01-10 20:00:19'); +INSERT INTO `sys_oper_log` VALUES (1612781392805097473, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612781375180632066\",\"articleTitle\":\"测试文章\",\"articleContent\":\"这一次我一定要成功\",\"type\":1,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:00:23'); +INSERT INTO `sys_oper_log` VALUES (1612783832598179842, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":2,\"configKey\":\"qiniu\",\"accessKey\":\"DLH4FnygkdCqfAKwQFxFwx2QrGTf0pJGDzDXYNQh\",\"secretKey\":\"zRpC1Xdf0Dc98u470lLh1k0XoE_l40ZDWF6gpNwn\",\"bucketName\":\"420-image\",\"prefix\":\"\",\"endpoint\":\"s3-cn-north-1.qiniucs.com\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"1\",\"region\":\"\",\"ext1\":\"\",\"remark\":null,\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:10:04'); +INSERT INTO `sys_oper_log` VALUES (1612783883315703809, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":2,\"configKey\":\"qiniu\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:10:17'); +INSERT INTO `sys_oper_log` VALUES (1612783932170956802, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612783932108042241\",\"url\":\"http://420-image.s3-cn-north-1.qiniucs.com/2023/01/10/e9b738e3ea884802aaeb1fd9eb4efe3a.jpg\",\"fileName\":\"QQ图片20210424191204.jpg\"}}', 0, '', '2023-01-10 20:10:28'); +INSERT INTO `sys_oper_log` VALUES (1612786512188010498, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":\"WmyGewy8Cv3vJNQD\",\"secretKey\":\"LMBPaqaR2DJKlabmjZg5ys3pCJzSE82v\",\"bucketName\":\"ruoyi\",\"prefix\":\"\",\"endpoint\":\"127.0.0.1:9000\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"1\",\"region\":\"\",\"ext1\":\"\",\"remark\":null,\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:20:43'); +INSERT INTO `sys_oper_log` VALUES (1612786736969150465, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":\"WmyGewy8Cv3vJNQD\",\"secretKey\":\"LMBPaqaR2DJKlabmjZg5ys3pCJzSE82v\",\"bucketName\":\"ruoyi\",\"prefix\":\"\",\"endpoint\":\"127.0.0.1:9000\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"1\",\"region\":\"\",\"ext1\":\"\",\"remark\":\"\",\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:21:37'); +INSERT INTO `sys_oper_log` VALUES (1612786747094200321, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:21:39'); +INSERT INTO `sys_oper_log` VALUES (1612786835128446978, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1612786835128446977\",\"url\":\"http://127.0.0.1:9000/ruoyi/2023/01/10/602f608660bf4ce9ac85fb4aceee2a04.jpg\",\"fileName\":\"QQ图片20210424183727.jpg\"}}', 0, '', '2023-01-10 20:22:00'); +INSERT INTO `sys_oper_log` VALUES (1612787286074847234, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":3,\"configKey\":\"aliyun\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:23:48'); +INSERT INTO `sys_oper_log` VALUES (1612787314940047362, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612783932108042241', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:23:55'); +INSERT INTO `sys_oper_log` VALUES (1612787323756474369, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612786835128446977', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 20:23:57'); +INSERT INTO `sys_oper_log` VALUES (1612801785548894210, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:21:24\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:21:24\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1612801785548894209\",\"menuName\":\"消息管理\",\"orderNum\":2,\"path\":\"/message\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"message\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:21:25'); +INSERT INTO `sys_oper_log` VALUES (1612801946857631754, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_comment\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:22:03'); +INSERT INTO `sys_oper_log` VALUES (1612802180614582274, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:22:58\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:22:58\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"pk\":true,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:22:58\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"pk\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:22:58\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:22:59'); +INSERT INTO `sys_oper_log` VALUES (1612802976722841602, '字典类型', 1, 'com.zhi.web.controller.system.SysDictTypeController.add()', 'POST', 1, 'admin', '', '/system/dict/type', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:26:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:26:08\",\"dictId\":\"1612802976722841601\",\"dictName\":\"评论类型\",\"dictType\":\"commentype\",\"status\":\"0\",\"remark\":\"评论类型\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:26:09'); +INSERT INTO `sys_oper_log` VALUES (1612803250258571266, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:27:13\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:27:13\",\"dictCode\":\"1612803250258571265\",\"dictSort\":0,\"dictLabel\":\"文章\",\"dictValue\":\"1\",\"dictType\":\"commentype\",\"cssClass\":null,\"listClass\":\"primary\",\"isDefault\":null,\"status\":\"0\",\"remark\":\"文章\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:27:14'); +INSERT INTO `sys_oper_log` VALUES (1612803354105344002, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:27:38\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:27:38\",\"dictCode\":\"1612803354046623746\",\"dictSort\":0,\"dictLabel\":\"友链\",\"dictValue\":\"2\",\"dictType\":\"commentype\",\"cssClass\":null,\"listClass\":\"info\",\"isDefault\":null,\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:27:39'); +INSERT INTO `sys_oper_log` VALUES (1612803386770583554, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:27:39\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:27:46\",\"dictCode\":\"1612803354046623746\",\"dictSort\":0,\"dictLabel\":\"友链\",\"dictValue\":\"2\",\"dictType\":\"commentype\",\"cssClass\":null,\"listClass\":\"success\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":null,\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:27:47'); +INSERT INTO `sys_oper_log` VALUES (1612803473668173825, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:28:07\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:28:07\",\"dictCode\":\"1612803473601064961\",\"dictSort\":0,\"dictLabel\":\"说说\",\"dictValue\":\"3\",\"dictType\":\"commentype\",\"cssClass\":null,\"listClass\":\"warning\",\"isDefault\":null,\"status\":\"0\",\"remark\":\"说说\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:28:07'); +INSERT INTO `sys_oper_log` VALUES (1612803517423153154, '字典数据', 2, 'com.zhi.web.controller.system.SysDictDataController.edit()', 'PUT', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:27:39\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:28:17\",\"dictCode\":\"1612803354046623746\",\"dictSort\":0,\"dictLabel\":\"友链\",\"dictValue\":\"2\",\"dictType\":\"commentype\",\"cssClass\":null,\"listClass\":\"success\",\"isDefault\":\"N\",\"status\":\"0\",\"remark\":\"友链\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:28:18'); +INSERT INTO `sys_oper_log` VALUES (1612805147610705921, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:34:46\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:34:46\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"pk\":true,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:34:46\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"pk\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:34:46\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:34:46'); +INSERT INTO `sys_oper_log` VALUES (1612808863181041666, '字典类型', 1, 'com.zhi.web.controller.system.SysDictTypeController.add()', 'POST', 1, 'admin', '', '/system/dict/type', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:49:32\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:49:32\",\"dictId\":\"1612808863113932801\",\"dictName\":\"评论状态\",\"dictType\":\"comment_status\",\"status\":\"0\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:49:32'); +INSERT INTO `sys_oper_log` VALUES (1612808926083018754, '字典类型', 2, 'com.zhi.web.controller.system.SysDictTypeController.edit()', 'PUT', 1, 'admin', '', '/system/dict/type', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:26:09\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:49:47\",\"dictId\":13,\"dictName\":\"评论类型\",\"dictType\":\"commen_type\",\"status\":\"0\",\"remark\":\"评论类型\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:49:47'); +INSERT INTO `sys_oper_log` VALUES (1612809114323382273, '字典类型', 2, 'com.zhi.web.controller.system.SysDictTypeController.edit()', 'PUT', 1, 'admin', '', '/system/dict/type', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:49:32\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:50:32\",\"dictId\":14,\"dictName\":\"评论状态\",\"dictType\":\"comment_status\",\"status\":\"0\",\"remark\":\"评论状态\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:50:32'); +INSERT INTO `sys_oper_log` VALUES (1612809327414996993, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:51:22\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:51:22\",\"dictCode\":\"1612809327352082433\",\"dictSort\":0,\"dictLabel\":\"审核通过\",\"dictValue\":\"1\",\"dictType\":\"comment_status\",\"cssClass\":null,\"listClass\":\"success\",\"isDefault\":null,\"status\":\"0\",\"remark\":\"审核通过\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:51:23'); +INSERT INTO `sys_oper_log` VALUES (1612809446243823617, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:51:51\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:51:51\",\"dictCode\":\"1612809446180909057\",\"dictSort\":0,\"dictLabel\":\"审核中\",\"dictValue\":\"2\",\"dictType\":\"comment_status\",\"cssClass\":null,\"listClass\":\"primary\",\"isDefault\":null,\"status\":\"0\",\"remark\":\"审核中\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:51:51'); +INSERT INTO `sys_oper_log` VALUES (1612809531824402434, '字典数据', 1, 'com.zhi.web.controller.system.SysDictDataController.add()', 'POST', 1, 'admin', '', '/system/dict/data', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:52:11\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:52:11\",\"dictCode\":\"1612809531757293569\",\"dictSort\":0,\"dictLabel\":\"未通过审核\",\"dictValue\":\"3\",\"dictType\":\"comment_status\",\"cssClass\":null,\"listClass\":\"danger\",\"isDefault\":null,\"status\":\"0\",\"remark\":\"审核不通过\",\"default\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:52:12'); +INSERT INTO `sys_oper_log` VALUES (1612809866806685698, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:53:31\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:53:31\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"pk\":true,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:53:31\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"pk\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:53:31\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:53:31'); +INSERT INTO `sys_oper_log` VALUES (1612809899010551811, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_comment', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:53:39'); +INSERT INTO `sys_oper_log` VALUES (1612810027997982722, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:54:09\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:54:09\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"pk\":true,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:54:09\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"superColumn\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"pk\":false,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 21:54:09\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 21:54:10'); +INSERT INTO `sys_oper_log` VALUES (1612810101087924225, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_comment\"}', '', 0, '', '2023-01-10 21:54:27'); +INSERT INTO `sys_oper_log` VALUES (1612811822207893505, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_comment', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:01:18'); +INSERT INTO `sys_oper_log` VALUES (1612811903199903745, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:01:36\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:01:36\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"list\":true,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:01:36\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"list\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:01:36\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:01:37'); +INSERT INTO `sys_oper_log` VALUES (1612812816593502209, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_comment', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:05:15'); +INSERT INTO `sys_oper_log` VALUES (1612812888873943042, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:05:31\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:05:31\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"insert\":false,\"usableColumn\":false,\"edit\":true,\"superColumn\":false,\"capJavaField\":\"Id\",\"query\":false,\"increment\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:05:31\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"insert\":true,\"usableColumn\":false,\"edit\":true,\"superColumn\":false,\"capJavaField\":\"UserId\",\"query\":true,\"increment\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:05:31\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:05:32'); +INSERT INTO `sys_oper_log` VALUES (1612816099190022146, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_comment', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:18:17'); +INSERT INTO `sys_oper_log` VALUES (1612816206497095682, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:18:42\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:18:42\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"superColumn\":false,\"edit\":true,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:18:42\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"superColumn\":false,\"edit\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:18:42\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:18:43'); +INSERT INTO `sys_oper_log` VALUES (1612818046714429441, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_comment', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:26:02'); +INSERT INTO `sys_oper_log` VALUES (1612818139198832641, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:26:23\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:26:23\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:26:23\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:26:23\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:26:24'); +INSERT INTO `sys_oper_log` VALUES (1612818295013031937, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:27:00\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1612801946723414017\",\"tableName\":\"blog_comment\",\"tableComment\":\"评论管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Comment\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"comment\",\"businessName\":\"comment\",\"functionName\":\"评论管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:27:00\",\"columnId\":\"1612801946790522881\",\"tableId\":\"1612801946723414017\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"query\":false,\"increment\":true,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:27:00\",\"columnId\":\"1612801946790522882\",\"tableId\":\"1612801946723414017\",\"columnName\":\"user_id\",\"columnComment\":\"评论用户Id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"query\":true,\"increment\":false,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:22:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-10 22:27:00\",\"columnId\":\"1612801946790522883\",\"tableId\":\"1612801946723414017\",\"columnName\":\"comment_content\",\"columnComment\":\"评论内容\",\"columnType\":\"text\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-10 22:27:01'); +INSERT INTO `sys_oper_log` VALUES (1613044955473854465, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:58:57\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:27:40\",\"parentName\":null,\"parentId\":\"1612801785548894209\",\"children\":[],\"menuId\":\"1612810100827877376\",\"menuName\":\"评论管理\",\"orderNum\":1,\"path\":\"comment\",\"component\":\"comment/comment/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"comment:comment:list\",\"icon\":\"documentation\",\"remark\":\"评论管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:27:41'); +INSERT INTO `sys_oper_log` VALUES (1613045082510934017, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:21:25\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:28:11\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1612801785548894209\",\"menuName\":\"消息管理\",\"orderNum\":3,\"path\":\"/message\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"message\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:28:11'); +INSERT INTO `sys_oper_log` VALUES (1613045143236067330, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-10 21:21:25\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:28:25\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1612801785548894209\",\"menuName\":\"消息管理\",\"orderNum\":2,\"path\":\"/message\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"message\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:28:26'); +INSERT INTO `sys_oper_log` VALUES (1613045202312839170, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:28:39\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":1,\"menuName\":\"系统管理\",\"orderNum\":4,\"path\":\"system\",\"component\":null,\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"\",\"icon\":\"system\",\"remark\":\"系统管理目录\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:28:40'); +INSERT INTO `sys_oper_log` VALUES (1613045244880830466, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:28:49\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":2,\"menuName\":\"系统监控\",\"orderNum\":5,\"path\":\"monitor\",\"component\":null,\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"\",\"icon\":\"monitor\",\"remark\":\"系统监控目录\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:28:50'); +INSERT INTO `sys_oper_log` VALUES (1613045275205648385, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:28:57\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":3,\"menuName\":\"系统工具\",\"orderNum\":6,\"path\":\"tool\",\"component\":null,\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"\",\"icon\":\"tool\",\"remark\":\"系统工具目录\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:28:57'); +INSERT INTO `sys_oper_log` VALUES (1613045301604597761, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:29:03\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":5,\"menuName\":\"测试菜单\",\"orderNum\":7,\"path\":\"demo\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"star\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:29:04'); +INSERT INTO `sys_oper_log` VALUES (1613047100537389058, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"付费\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612781375180632066\",\"articleTitle\":\"测试文章\",\"articleContent\":\"这一次我一定要成功\",\"type\":1,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:36:12'); +INSERT INTO `sys_oper_log` VALUES (1613047998453989377, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1612030689601957890', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"操作失败\",\"data\":null}', 0, '', '2023-01-11 13:39:46'); +INSERT INTO `sys_oper_log` VALUES (1613048040078262274, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613048040015347713\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/98212b3ebd05452daf5fdb3d53898124.jpg\",\"fileName\":\"QQ图片20210424183800.jpg\"}}', 0, '', '2023-01-11 13:39:56'); +INSERT INTO `sys_oper_log` VALUES (1613048048580116481, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1613048040015347713\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:39:58'); +INSERT INTO `sys_oper_log` VALUES (1613049235983384578, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 13:44:41\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:44:41\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1613049235916275714\",\"menuName\":\"个人中心\",\"orderNum\":10,\"path\":\"system/user/profile\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"user\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:44:42'); +INSERT INTO `sys_oper_log` VALUES (1613049363242762242, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 13:44:42\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:45:11\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1613049235916275714\",\"menuName\":\"个人中心\",\"orderNum\":10,\"path\":\"user/profile\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"user\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:45:12'); +INSERT INTO `sys_oper_log` VALUES (1613049556528873474, '个人信息', 2, 'com.zhi.web.controller.system.SysProfileController.updateProfile()', 'PUT', 1, 'admin', '', '/system/user/profile', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 13:45:57\",\"userId\":1,\"deptId\":null,\"userName\":null,\"nickName\":\"water-之\",\"userType\":\"sys_user\",\"email\":\"2831826106@qq.com\",\"phonenumber\":\"18888888888\",\"sex\":\"0\",\"avatar\":null,\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-11 12:29:26\",\"remark\":\"管理员\",\"dept\":{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"parentName\":null,\"parentId\":101,\"children\":[],\"deptId\":103,\"deptName\":\"研发部门\",\"orderNum\":1,\"leader\":\"若依\",\"phone\":null,\"email\":null,\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100,101\"},\"roles\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"roleId\":1,\"roleName\":\"超级管理员\",\"roleKey\":\"admin\",\"roleSort\":1,\"dataScope\":\"1\",\"menuCheckStrictly\":null,\"deptCheckStrictly\":null,\"status\":\"0\",\"delFlag\":null,\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":null,\"permissions\":null,\"admin\":true}],\"roleIds\":null,\"postIds\":null,\"roleId\":null,\"admin\":true}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 13:45:58'); +INSERT INTO `sys_oper_log` VALUES (1613097813158187009, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_message\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 16:57:43'); +INSERT INTO `sys_oper_log` VALUES (1613098320635416577, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 16:59:44\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1612801785548894209\"},\"tableId\":\"1613097812961054721\",\"tableName\":\"blog_message\",\"tableComment\":\"留言管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Message\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"message\",\"businessName\":\"message\",\"functionName\":\"留言管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 16:57:43\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 16:59:44\",\"columnId\":\"1613097813036552193\",\"tableId\":\"1613097812961054721\",\"columnName\":\"id\",\"columnComment\":\"主键id\",\"columnType\":\"bigint(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 16:57:43\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 16:59:44\",\"columnId\":\"1613097813036552194\",\"tableId\":\"1613097812961054721\",\"columnName\":\"nickname\",\"columnComment\":\"昵称\",\"columnType\":\"varchar(50)\",\"javaType\":\"String\",\"javaField\":\"nickname\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"increment\":false,\"query\":true,\"capJavaField\":\"Nickname\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 16:57:43\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 16:59:44\",\"columnId\":\"1613097813036552195\",\"tableId\":\"1613097812961054721\",\"columnName\":\"avatar\",\"columnComment\":\"头像\",\"columnType\":\"varchar(', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 16:59:44'); +INSERT INTO `sys_oper_log` VALUES (1613098352000421890, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_message\"}', '', 0, '', '2023-01-11 16:59:52'); +INSERT INTO `sys_oper_log` VALUES (1613099785902972929, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 17:03:25\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 17:05:33\",\"parentName\":null,\"parentId\":\"1612801785548894209\",\"children\":[],\"menuId\":\"1613098351056703488\",\"menuName\":\"留言管理\",\"orderNum\":1,\"path\":\"message\",\"component\":\"message/message/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"message:message:list\",\"icon\":\"checkbox\",\"remark\":\"留言管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 17:05:34'); +INSERT INTO `sys_oper_log` VALUES (1613106317432512514, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 17:03:25\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 17:31:30\",\"parentName\":null,\"parentId\":\"1612801785548894209\",\"children\":[],\"menuId\":\"1613098351056703488\",\"menuName\":\"留言管理\",\"orderNum\":2,\"path\":\"message\",\"component\":\"message/message/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"message:message:list\",\"icon\":\"checkbox\",\"remark\":\"留言管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 17:31:31'); +INSERT INTO `sys_oper_log` VALUES (1613139021398073346, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 19:41:28\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 19:41:28\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1613139021339353090\",\"menuName\":\"界面管理\",\"orderNum\":3,\"path\":\"/website\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"theme\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 19:41:28'); +INSERT INTO `sys_oper_log` VALUES (1613157470555922433, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 20:54:46\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 20:54:46\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613157470488813570\",\"menuName\":\"网站管理\",\"orderNum\":1,\"path\":\"website\",\"component\":\"website\",\"queryParam\":\"website\",\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"international\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 20:54:47'); +INSERT INTO `sys_oper_log` VALUES (1613157589825150978, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 20:54:47\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 20:55:15\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613157470488813570\",\"menuName\":\"网站管理\",\"orderNum\":1,\"path\":\"website\",\"component\":\"website\",\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"international\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 20:55:15'); +INSERT INTO `sys_oper_log` VALUES (1613163573985464322, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613163573826080770\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/378641b3b92149d88409807b0a76c9e4.jpg\",\"fileName\":\"QQ图片20230111154502.jpg\"}}', 0, '', '2023-01-11 21:19:02'); +INSERT INTO `sys_oper_log` VALUES (1613163746723680257, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613163746656571393\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/c93f7a5406b344a1bbe5e62f1ce736b3.jpg\",\"fileName\":\"QQ图片20230111154502.jpg\"}}', 0, '', '2023-01-11 21:19:43'); +INSERT INTO `sys_oper_log` VALUES (1613166340854566914, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613166340791652354\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/5e19b20605c94fedb072adbf76cefb6f.jpg\",\"fileName\":\"QQ图片20230111154502.jpg\"}}', 0, '', '2023-01-11 21:30:02'); +INSERT INTO `sys_oper_log` VALUES (1613170007288594433, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613170007087267841\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/d2a1e401f0aa41ad93b3df32a66840d9.jpg\",\"fileName\":\"QQ图片20230111154502.jpg\"}}', 0, '', '2023-01-11 21:44:36'); +INSERT INTO `sys_oper_log` VALUES (1613170095004073985, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613170094936965121\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/d917e0eddca44f41ba8e4befd51758c6.jpg\",\"fileName\":\"QQ图片20230111154502.jpg\"}}', 0, '', '2023-01-11 21:44:57'); +INSERT INTO `sys_oper_log` VALUES (1613170123965743106, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613170123965743105\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/a6e94d542f824079a5106f43c5c9d112.jpg\",\"fileName\":\"wei.jpg\"}}', 0, '', '2023-01-11 21:45:03'); +INSERT INTO `sys_oper_log` VALUES (1613170158212235266, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613170158132543490\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/ea557fe94c634ae1afb36c9ab81c9e6c.jpg\",\"fileName\":\"zhi.jpg\"}}', 0, '', '2023-01-11 21:45:12'); +INSERT INTO `sys_oper_log` VALUES (1613171390939152385, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 21:50:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 21:50:05\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613171390876237826\",\"menuName\":\"页面管理\",\"orderNum\":2,\"path\":\"pages\",\"component\":\"pages\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"education\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 21:50:06'); +INSERT INTO `sys_oper_log` VALUES (1613173787618983938, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1613166340791652354', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 21:59:37'); +INSERT INTO `sys_oper_log` VALUES (1613182408033599489, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1613166340791652354', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"操作失败\",\"data\":null}', 0, '', '2023-01-11 22:33:52'); +INSERT INTO `sys_oper_log` VALUES (1613182450786140161, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613182450719031297\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/11/f031de41bc1845519aabb95d9bede0fd.jpg\",\"fileName\":\"QQ图片20230111154502.jpg\"}}', 0, '', '2023-01-11 22:34:02'); +INSERT INTO `sys_oper_log` VALUES (1613183158545580033, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-11 21:50:06\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-11 22:36:51\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613171390876237826\",\"menuName\":\"页面管理\",\"orderNum\":2,\"path\":\"pages\",\"component\":\"page\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"1\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"education\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-11 22:36:51'); +INSERT INTO `sys_oper_log` VALUES (1613391695351697409, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_page\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:25:30'); +INSERT INTO `sys_oper_log` VALUES (1613395308337745922, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:39:51\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":null},\"tableId\":\"1613391695125204993\",\"tableName\":\"blog_page\",\"tableComment\":\"页面\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"BlogPage\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.system\",\"moduleName\":\"system\",\"businessName\":\"page\",\"functionName\":\"页面\",\"functionAuthor\":\"ruoyi\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:39:51\",\"columnId\":\"1613391695188119553\",\"tableId\":\"1613391695125204993\",\"columnName\":\"id\",\"columnComment\":\"页面id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"increment\":true,\"capJavaField\":\"Id\",\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:39:51\",\"columnId\":\"1613391695188119554\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_name\",\"columnComment\":\"页面名\",\"columnType\":\"varchar(10)\",\"javaType\":\"String\",\"javaField\":\"pageName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"increment\":false,\"capJavaField\":\"PageName\",\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:39:51\",\"columnId\":\"1613391695255228418\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_label\",\"columnComment\":\"页面标签\",\"columnType\":\"varchar(20)\",\"javaType\":\"S', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:39:52'); +INSERT INTO `sys_oper_log` VALUES (1613395321428168707, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_page', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:39:55'); +INSERT INTO `sys_oper_log` VALUES (1613395528807141378, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:40:44\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"},\"tableId\":\"1613391695125204993\",\"tableName\":\"blog_page\",\"tableComment\":\"页面管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Page\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"page\",\"businessName\":\"page\",\"functionName\":\"页面管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:40:44\",\"columnId\":\"1613391695188119553\",\"tableId\":\"1613391695125204993\",\"columnName\":\"id\",\"columnComment\":\"页面id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"increment\":true,\"capJavaField\":\"Id\",\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:40:44\",\"columnId\":\"1613391695188119554\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_name\",\"columnComment\":\"页面名\",\"columnType\":\"varchar(10)\",\"javaType\":\"String\",\"javaField\":\"pageName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"increment\":false,\"capJavaField\":\"PageName\",\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:40:44\",\"columnId\":\"1613391695255228418\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_label\",\"columnComment\":\"页面标签\",\"columnType\":\"varchar(20)\",\"j', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:40:44'); +INSERT INTO `sys_oper_log` VALUES (1613395547211747329, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_page\"}', '', 0, '', '2023-01-12 12:40:49'); +INSERT INTO `sys_oper_log` VALUES (1613395870345121794, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1613171390876237826', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:42:06'); +INSERT INTO `sys_oper_log` VALUES (1613396059499843586, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:42:50\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"},\"tableId\":\"1613391695125204993\",\"tableName\":\"blog_page\",\"tableComment\":\"页面管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Page\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"page\",\"businessName\":\"page\",\"functionName\":\"页面管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:42:50\",\"columnId\":\"1613391695188119553\",\"tableId\":\"1613391695125204993\",\"columnName\":\"id\",\"columnComment\":\"页面id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"increment\":true,\"capJavaField\":\"Id\",\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:42:50\",\"columnId\":\"1613391695188119554\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_name\",\"columnComment\":\"页面名\",\"columnType\":\"varchar(10)\",\"javaType\":\"String\",\"javaField\":\"pageName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"increment\":false,\"capJavaField\":\"PageName\",\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:42:50\",\"columnId\":\"1613391695255228418\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_label\",\"columnComment\":\"页面标签\",\"columnType\":\"varchar(20)\",\"j', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:42:51'); +INSERT INTO `sys_oper_log` VALUES (1613397864447266818, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:01\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"},\"tableId\":\"1613391695125204993\",\"tableName\":\"blog_page\",\"tableComment\":\"页面管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"BlogPage\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"page\",\"businessName\":\"page\",\"functionName\":\"页面管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:01\",\"columnId\":\"1613391695188119553\",\"tableId\":\"1613391695125204993\",\"columnName\":\"id\",\"columnComment\":\"页面id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"increment\":true,\"capJavaField\":\"Id\",\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:01\",\"columnId\":\"1613391695188119554\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_name\",\"columnComment\":\"页面名\",\"columnType\":\"varchar(10)\",\"javaType\":\"String\",\"javaField\":\"pageName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"increment\":false,\"capJavaField\":\"PageName\",\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:01\",\"columnId\":\"1613391695255228418\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_label\",\"columnComment\":\"页面标签\",\"columnType\":\"varchar(20)', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:50:01'); +INSERT INTO `sys_oper_log` VALUES (1613397888925224961, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:06\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"},\"tableId\":\"1613391695125204993\",\"tableName\":\"blog_page\",\"tableComment\":\"页面管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"BlogPage\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"page\",\"businessName\":\"page\",\"functionName\":\"页面管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:06\",\"columnId\":\"1613391695188119553\",\"tableId\":\"1613391695125204993\",\"columnName\":\"id\",\"columnComment\":\"页面id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"increment\":true,\"capJavaField\":\"Id\",\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:06\",\"columnId\":\"1613391695188119554\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_name\",\"columnComment\":\"页面名\",\"columnType\":\"varchar(10)\",\"javaType\":\"String\",\"javaField\":\"pageName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"increment\":false,\"capJavaField\":\"PageName\",\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:25:30\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:50:06\",\"columnId\":\"1613391695255228418\",\"tableId\":\"1613391695125204993\",\"columnName\":\"page_label\",\"columnComment\":\"页面标签\",\"columnType\":\"varchar(20)', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:50:07'); +INSERT INTO `sys_oper_log` VALUES (1613398656654823426, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_page\"}', '', 0, '', '2023-01-12 12:53:10'); +INSERT INTO `sys_oper_log` VALUES (1613399563744395265, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:55:15\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 12:56:46\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613398656495439872\",\"menuName\":\"页面管理\",\"orderNum\":1,\"path\":\"page\",\"component\":\"page/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"page:page:list\",\"icon\":\"#\",\"remark\":\"页面管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:56:46'); +INSERT INTO `sys_oper_log` VALUES (1613399733093613570, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613399733030699010\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/12/25ee313c2e774b64913d6e3d65cd696d.jpg\",\"fileName\":\"bg.jpg\"}}', 0, '', '2023-01-12 12:57:27'); +INSERT INTO `sys_oper_log` VALUES (1613399741121511426, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"pageName\":\"首页\",\"pageLabel\":\"home\",\"pageCover\":\"1613399733030699010\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 12:57:28'); +INSERT INTO `sys_oper_log` VALUES (1613403777094647809, '页面管理', 3, 'com.zhi.blog.controller.BlogPageController.remove()', 'DELETE', 1, 'admin', '', '/page/page/11', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 13:13:31'); +INSERT INTO `sys_oper_log` VALUES (1613408128760545281, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_friend_link\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 13:30:48'); +INSERT INTO `sys_oper_log` VALUES (1613408579778248706, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:32:35\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":null},\"tableId\":\"1613408128559218689\",\"tableName\":\"blog_friend_link\",\"tableComment\":\"友链管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"FriendLink\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"FriendLink\",\"businessName\":\"friendLink\",\"functionName\":\"友链管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:30:48\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:32:35\",\"columnId\":\"1613408128626327554\",\"tableId\":\"1613408128559218689\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"capJavaField\":\"Id\",\"increment\":true,\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:30:48\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:32:35\",\"columnId\":\"1613408128626327555\",\"tableId\":\"1613408128559218689\",\"columnName\":\"link_name\",\"columnComment\":\"链接名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"linkName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"capJavaField\":\"LinkName\",\"increment\":false,\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:30:48\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:32:35\",\"columnId\":\"1613408128626327556\",\"tableId\":\"1613408128559218689\",\"columnName\":\"link_avatar\",\"columnComment\":\"链接头像\",\"columnType\":\"varchar(25', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 13:32:36'); +INSERT INTO `sys_oper_log` VALUES (1613408725907800065, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:33:10\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613139021339353090\"},\"tableId\":\"1613408128559218689\",\"tableName\":\"blog_friend_link\",\"tableComment\":\"友链管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"FriendLink\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"friendLink\",\"businessName\":\"friendLink\",\"functionName\":\"友链管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:30:48\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:33:10\",\"columnId\":\"1613408128626327554\",\"tableId\":\"1613408128559218689\",\"columnName\":\"id\",\"columnComment\":\"\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"superColumn\":false,\"insert\":false,\"edit\":true,\"capJavaField\":\"Id\",\"increment\":true,\"query\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:30:48\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:33:10\",\"columnId\":\"1613408128626327555\",\"tableId\":\"1613408128559218689\",\"columnName\":\"link_name\",\"columnComment\":\"链接名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"linkName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"superColumn\":false,\"insert\":true,\"edit\":true,\"capJavaField\":\"LinkName\",\"increment\":false,\"query\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:30:48\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:33:10\",\"columnId\":\"1613408128626327556\",\"tableId\":\"1613408128559218689\",\"columnName\":\"link_avatar\",\"columnComment\":\"链接头像\",\"column', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 13:33:11'); +INSERT INTO `sys_oper_log` VALUES (1613408736947208193, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_friend_link\"}', '', 0, '', '2023-01-12 13:33:13'); +INSERT INTO `sys_oper_log` VALUES (1613409851134783489, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 12:55:15\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:37:38\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613398656495439872\",\"menuName\":\"页面管理\",\"orderNum\":2,\"path\":\"page\",\"component\":\"page/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"page:page:list\",\"icon\":\"education\",\"remark\":\"页面管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 13:37:39'); +INSERT INTO `sys_oper_log` VALUES (1613409899566411778, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-12 13:36:15\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-12 13:37:50\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1613408736209010688\",\"menuName\":\"友链管理\",\"orderNum\":3,\"path\":\"friendLink\",\"component\":\"friendLink/friendLink/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"friendLink:friendLink:list\",\"icon\":\"people\",\"remark\":\"友链管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-12 13:37:50'); +INSERT INTO `sys_oper_log` VALUES (1613813536683724801, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_talk\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:21:45'); +INSERT INTO `sys_oper_log` VALUES (1613813815252619265, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:22:51\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:22:51\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1613813815185510401\",\"menuName\":\"说说管理\",\"orderNum\":5,\"path\":\"talk\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"wechat\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:22:51'); +INSERT INTO `sys_oper_log` VALUES (1613814203334791170, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:24:23\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613813815185510401\"},\"tableId\":\"1613813536490786817\",\"tableName\":\"blog_talk\",\"tableComment\":\"说说管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Talk\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"talk\",\"businessName\":\"talk\",\"functionName\":\"说说管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:21:45\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:24:23\",\"columnId\":\"1613813536553701378\",\"tableId\":\"1613813536490786817\",\"columnName\":\"id\",\"columnComment\":\"说说id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"pk\":true,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:21:45\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:24:23\",\"columnId\":\"1613813536553701379\",\"tableId\":\"1613813536490786817\",\"columnName\":\"user_id\",\"columnComment\":\"用户id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"pk\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:21:45\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:24:23\",\"columnId\":\"1613813536553701380\",\"tableId\":\"1613813536490786817\",\"columnName\":\"content\",\"columnComment\":\"说说内容\",\"columnType\":\"varchar(2000)\",\"javaType\":\"Stri', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:24:24'); +INSERT INTO `sys_oper_log` VALUES (1613814685134491649, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_talk', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:26:19'); +INSERT INTO `sys_oper_log` VALUES (1613814749819047937, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_talk', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:26:34'); +INSERT INTO `sys_oper_log` VALUES (1613814792953270273, '代码生成', 3, 'com.zhi.generator.controller.GenController.remove()', 'DELETE', 1, 'admin', '', '/tool/gen/1613813536490786817', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:26:45'); +INSERT INTO `sys_oper_log` VALUES (1613814814562324486, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '127.0.0.1', '内网IP', '\"blog_talk\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:26:50'); +INSERT INTO `sys_oper_log` VALUES (1613815252976144385, '代码生成', 2, 'com.zhi.generator.controller.GenController.synchDb()', 'GET', 1, 'admin', '', '/tool/gen/synchDb/blog_talk', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:28:34'); +INSERT INTO `sys_oper_log` VALUES (1613816292383395842, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:32:42\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613813815185510401\"},\"tableId\":\"1613814814495215617\",\"tableName\":\"blog_talk\",\"tableComment\":\"说说管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Talk\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"talk\",\"businessName\":\"talk\",\"functionName\":\"说说管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:32:42\",\"columnId\":\"1613814814495215618\",\"tableId\":\"1613814814495215617\",\"columnName\":\"id\",\"columnComment\":\"说说id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"pk\":true,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:32:42\",\"columnId\":\"1613814814495215619\",\"tableId\":\"1613814814495215617\",\"columnName\":\"user_id\",\"columnComment\":\"用户id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"pk\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:32:42\",\"columnId\":\"1613814814495215620\",\"tableId\":\"1613814814495215617\",\"columnName\":\"content\",\"columnComment\":\"说说内容\",\"columnType\":\"varchar(2000)\",\"javaType\":\"Stri', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:32:42'); +INSERT INTO `sys_oper_log` VALUES (1613816525758664706, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:33:37\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613813815185510401\"},\"tableId\":\"1613814814495215617\",\"tableName\":\"blog_talk\",\"tableComment\":\"说说管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Talk\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"talk\",\"businessName\":\"talk\",\"functionName\":\"说说管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:33:37\",\"columnId\":\"1613814814495215618\",\"tableId\":\"1613814814495215617\",\"columnName\":\"id\",\"columnComment\":\"说说id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":false,\"pk\":true,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:33:37\",\"columnId\":\"1613814814495215619\",\"tableId\":\"1613814814495215617\",\"columnName\":\"user_id\",\"columnComment\":\"用户id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"usableColumn\":false,\"superColumn\":false,\"edit\":true,\"insert\":true,\"pk\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:33:37\",\"columnId\":\"1613814814495215620\",\"tableId\":\"1613814814495215617\",\"columnName\":\"content\",\"columnComment\":\"说说内容\",\"columnType\":\"varchar(2000)\",\"javaType\":\"Stri', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:33:38'); +INSERT INTO `sys_oper_log` VALUES (1613816543253106690, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '127.0.0.1', '内网IP', '{\"tables\":\"blog_talk\"}', '', 0, '', '2023-01-13 16:33:42'); +INSERT INTO `sys_oper_log` VALUES (1613818666359513089, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:42:07\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1613813815185510401\"},\"tableId\":\"1613814814495215617\",\"tableName\":\"blog_talk\",\"tableComment\":\"说说管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Talk\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"talk\",\"businessName\":\"talk\",\"functionName\":\"说说管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:42:07\",\"columnId\":\"1613814814495215618\",\"tableId\":\"1613814814495215617\",\"columnName\":\"id\",\"columnComment\":\"说说id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\",\"required\":true,\"list\":true,\"edit\":true,\"usableColumn\":false,\"superColumn\":false,\"pk\":true,\"insert\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:42:07\",\"columnId\":\"1613814814495215619\",\"tableId\":\"1613814814495215617\",\"columnName\":\"user_id\",\"columnComment\":\"用户id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"userId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"increment\":false,\"query\":true,\"capJavaField\":\"UserId\",\"required\":true,\"list\":true,\"edit\":true,\"usableColumn\":false,\"superColumn\":false,\"pk\":false,\"insert\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:26:50\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 16:42:07\",\"columnId\":\"1613814814495215620\",\"tableId\":\"1613814814495215617\",\"columnName\":\"content\",\"columnComment\":\"说说内容\",\"columnType\":\"varchar(2000)\",\"javaType\":\"Stri', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 16:42:08'); +INSERT INTO `sys_oper_log` VALUES (1613861852230512641, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 19:33:44\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 19:33:44\",\"parentName\":null,\"parentId\":\"1613813815185510401\",\"children\":[],\"menuId\":\"1613861852100489217\",\"menuName\":\"发布说说\",\"orderNum\":1,\"path\":\"talks\",\"component\":\"talk/talk\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"druid\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 19:33:44'); +INSERT INTO `sys_oper_log` VALUES (1613862048360361985, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:37:32\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 19:34:31\",\"parentName\":null,\"parentId\":\"1613813815185510401\",\"children\":[],\"menuId\":\"1613816542531686400\",\"menuName\":\"说说列表\",\"orderNum\":2,\"path\":\"talk\",\"component\":\"talk/talkList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"talk:talk:list\",\"icon\":\"#\",\"remark\":\"说说管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 19:34:31'); +INSERT INTO `sys_oper_log` VALUES (1613862119185379329, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:37:32\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 19:34:47\",\"parentName\":null,\"parentId\":\"1613813815185510401\",\"children\":[],\"menuId\":\"1613816542531686400\",\"menuName\":\"说说列表\",\"orderNum\":2,\"path\":\"talks\",\"component\":\"talk/talkList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"talk:talk:list\",\"icon\":\"#\",\"remark\":\"说说管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 19:34:48'); +INSERT INTO `sys_oper_log` VALUES (1613862142845448193, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 19:33:44\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-13 19:34:53\",\"parentName\":null,\"parentId\":\"1613813815185510401\",\"children\":[],\"menuId\":\"1613861852100489217\",\"menuName\":\"发布说说\",\"orderNum\":1,\"path\":\"talk\",\"component\":\"talk/talk\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"druid\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 19:34:54'); +INSERT INTO `sys_oper_log` VALUES (1613863062186553346, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613863062123638785\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/caf912a50d0d43c0a4c19f9b1cee09b2.jpg\",\"fileName\":\"QQ图片20210630102637.jpg\"}}', 0, '', '2023-01-13 19:38:33'); +INSERT INTO `sys_oper_log` VALUES (1613864916580626434, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613864916513517570\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/c796289e847c487da88241ea4f1b8e74.jpg\",\"fileName\":\"QQ图片20210630102637.jpg\"}}', 0, '', '2023-01-13 19:45:55'); +INSERT INTO `sys_oper_log` VALUES (1613864927099940865, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1613864916513517570\",\"articleTitle\":\"没错\",\"articleContent\":\"## 我没有错\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 19:45:57'); +INSERT INTO `sys_oper_log` VALUES (1613867081856512001, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/1', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 19:54:31'); +INSERT INTO `sys_oper_log` VALUES (1613876229541220354, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1613876229478305794\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/29f4a22badc84eeb96d82ff158607f39.jpg\",\"fileName\":\"1.jpg\"}}', 0, '', '2023-01-13 20:30:52'); +INSERT INTO `sys_oper_log` VALUES (1613876241180413953, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"userId\":1,\"content\":\"

123

\",\"images\":\"1612781375180632066,1613876229478305794\",\"isTop\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-13 20:30:55'); +INSERT INTO `sys_oper_log` VALUES (1613877614940815362, '用户头像', 2, 'com.zhi.web.controller.system.SysProfileController.avatar()', 'POST', 1, 'admin', '', '/system/user/profile/avatar', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"imgUrl\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg\"}}', 0, '', '2023-01-13 20:36:22'); +INSERT INTO `sys_oper_log` VALUES (1614114601379573762, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2022-01-24 23:34:59\",\"updateBy\":null,\"updateTime\":null,\"id\":1,\"userId\":1,\"content\":\"

123123\\\"[星星眼]\\\"

\",\"images\":\"[\\\"1612781375180632066\\\",\\\"1613876229478305794\\\"]\",\"isTop\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 12:18:04'); +INSERT INTO `sys_oper_log` VALUES (1614115754544730114, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614115754364375041\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/265c8d9461764d14964e65660d44789f.jpg\",\"fileName\":\"bg.jpg\"}}', 0, '', '2023-01-14 12:22:39'); +INSERT INTO `sys_oper_log` VALUES (1614115793014886403, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614115793014886402\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/cc9175f9061a410098477f44c8696095.jpg\",\"fileName\":\"1.jpg\"}}', 0, '', '2023-01-14 12:22:49'); +INSERT INTO `sys_oper_log` VALUES (1614116043825876995, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614116043825876994\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/901316157b53401ebf37c938acf6aaec.jpg\",\"fileName\":\"290072.jpg\"}}', 0, '', '2023-01-14 12:23:48'); +INSERT INTO `sys_oper_log` VALUES (1614116069310468097, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614116069247553538\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/11c17deb734846f88920a5945c3c754c.jpg\",\"fileName\":\"789672.jpg\"}}', 0, '', '2023-01-14 12:23:54'); +INSERT INTO `sys_oper_log` VALUES (1614116077447417858, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"发布说说\\\"[喜欢]\\\"\",\"images\":\"1614116043825876994,1614116069247553538\",\"isTop\":null,\"imgList\":[\"1614116043825876994\",\"1614116069247553538\"]}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( id, content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-01-14 12:23:56'); +INSERT INTO `sys_oper_log` VALUES (1614116344356204545, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"发布说说\\\"[喜欢]\\\"\",\"images\":\"1614116043825876994,1614116069247553538\",\"isTop\":null,\"imgList\":[\"1614116043825876994\",\"1614116069247553538\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:25:00'); +INSERT INTO `sys_oper_log` VALUES (1614116535259951106, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"发布说说\\\"[喜欢]\\\"\",\"images\":\"1614116043825876994,1614116069247553538\",\"isTop\":null,\"imgList\":[\"1614116043825876994\",\"1614116069247553538\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:25:45'); +INSERT INTO `sys_oper_log` VALUES (1614116812700577794, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"发布说说\\\"[喜欢]\\\"\",\"images\":\"1614116043825876994,1614116069247553538\",\"isTop\":null,\"imgList\":[\"1614116043825876994\",\"1614116069247553538\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:26:52'); +INSERT INTO `sys_oper_log` VALUES (1614117071782735873, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"发布说说\\\"[喜欢]\\\"\",\"images\":\"1614116043825876994,1614116069247553538\",\"isTop\":null,\"imgList\":[\"1614116043825876994\",\"1614116069247553538\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:27:53'); +INSERT INTO `sys_oper_log` VALUES (1614117106473824257, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"发布说说\\\"[喜欢]\\\"\",\"images\":\"1614116043825876994,1614116069247553538\",\"isTop\":null,\"imgList\":[\"1614116043825876994\",\"1614116069247553538\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:28:02'); +INSERT INTO `sys_oper_log` VALUES (1614117461110616066, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614117461043507201\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/1a74551d29ef4390914d17d814bcee8a.jpg\",\"fileName\":\"1161451.jpg\"}}', 0, '', '2023-01-14 12:29:26'); +INSERT INTO `sys_oper_log` VALUES (1614117497441677313, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614117497311653890\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/5af50c14fd6848a0865fa70c4ac5a18c.jpg\",\"fileName\":\"789672.jpg\"}}', 0, '', '2023-01-14 12:29:35'); +INSERT INTO `sys_oper_log` VALUES (1614117505574432770, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"123123\\\"[大哭]\\\"\",\"images\":\"1614117461043507201,1614117497311653890\",\"isTop\":null,\"imgList\":[\"1614117461043507201\",\"1614117497311653890\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:29:37'); +INSERT INTO `sys_oper_log` VALUES (1614117990893154305, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"123123\\\"[大哭]\\\"\",\"images\":\"1614117461043507201,1614117497311653890\",\"isTop\":null,\"imgList\":[\"1614117461043507201\",\"1614117497311653890\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:31:33'); +INSERT INTO `sys_oper_log` VALUES (1614118087483781122, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"123123\\\"[大哭]\\\"\",\"images\":\"1614117461043507201,1614117497311653890\",\"isTop\":null,\"imgList\":[\"1614117461043507201\",\"1614117497311653890\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:31:56'); +INSERT INTO `sys_oper_log` VALUES (1614118087508946945, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"123123\\\"[大哭]\\\"\",\"images\":\"1614117461043507201,1614117497311653890\",\"isTop\":null,\"imgList\":[\"1614117461043507201\",\"1614117497311653890\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:31:56'); +INSERT INTO `sys_oper_log` VALUES (1614118556285333506, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614118556243390465\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/4ed4a6ed89494d0aba239a5bdfdde5dd.jpg\",\"fileName\":\"1161451.jpg\"}}', 0, '', '2023-01-14 12:33:47'); +INSERT INTO `sys_oper_log` VALUES (1614118597087522817, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614118597024608258\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/24bae2bc59354bd7a855a17af5dbfb28.jpg\",\"fileName\":\"1.jpg\"}}', 0, '', '2023-01-14 12:33:57'); +INSERT INTO `sys_oper_log` VALUES (1614118607992713218, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"测试\\\"[害羞]\\\"\",\"images\":\"1614118556243390465,1614118597024608258\",\"isTop\":null,\"imgList\":[\"1614118556243390465\",\"1614118597024608258\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:34:00'); +INSERT INTO `sys_oper_log` VALUES (1614118780915478529, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"测试\\\"[害羞]\\\"\",\"images\":\"1614118556243390465,1614118597024608258\",\"isTop\":null,\"imgList\":[\"1614118556243390465\",\"1614118597024608258\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:34:41'); +INSERT INTO `sys_oper_log` VALUES (1614120033267490818, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614120033066164225\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/56e3989fd3184fe6b6d2c4a79d01468e.jpg\",\"fileName\":\"1161451.jpg\"}}', 0, '', '2023-01-14 12:39:39'); +INSERT INTO `sys_oper_log` VALUES (1614120071460823041, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614120071397908481\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/fd6a7a6910934b589c8d46a37a4213ac.jpg\",\"fileName\":\"1.jpg\"}}', 0, '', '2023-01-14 12:39:49'); +INSERT INTO `sys_oper_log` VALUES (1614120079522275329, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"测试\\\"[哦呼]\\\"\",\"images\":\"1614120033066164225,1614120071397908481\",\"isTop\":null,\"imgList\":[\"1614120033066164225\",\"1614120071397908481\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:39:51'); +INSERT INTO `sys_oper_log` VALUES (1614120201001902081, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"测试\\\"[哦呼]\\\"\",\"images\":\"1614120033066164225,1614120071397908481\",\"isTop\":null,\"imgList\":[\"1614120033066164225\",\"1614120071397908481\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:40:19'); +INSERT INTO `sys_oper_log` VALUES (1614120440593129474, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614120440526020610\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/86b5c0de5583496a9334e01cffaec4b3.jpg\",\"fileName\":\"1161451.jpg\"}}', 0, '', '2023-01-14 12:41:17'); +INSERT INTO `sys_oper_log` VALUES (1614120471761002497, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614120471693893634\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/c327173c17384b2b8af29b72df9cf4f9.jpg\",\"fileName\":\"789672.jpg\"}}', 0, '', '2023-01-14 12:41:24'); +INSERT INTO `sys_oper_log` VALUES (1614120563062611969, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"content\":\"测试\\\"[哦呼]\\\"\",\"images\":\"1614120440526020610,1614120471693893634\",\"isTop\":null,\"imgList\":[\"1614120440526020610\",\"1614120471693893634\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'user_id\' doesn\'t have a default value\n; Field \'user_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'user_id\' doesn\'t have a default value', '2023-01-14 12:41:46'); +INSERT INTO `sys_oper_log` VALUES (1614120954965794818, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614120954898685954\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/8ec8b962a88b473c8950181bebd60a41.jpg\",\"fileName\":\"1161451.jpg\"}}', 0, '', '2023-01-14 12:43:19'); +INSERT INTO `sys_oper_log` VALUES (1614121020434685953, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614121020367577090\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/09fe7b5d66364ec18091f404d065cc7a.jpg\",\"fileName\":\"789672.jpg\"}}', 0, '', '2023-01-14 12:43:35'); +INSERT INTO `sys_oper_log` VALUES (1614121049614458882, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":50,\"userId\":1,\"content\":\"最后一次\\\"[呲牙]\\\"\",\"images\":\"1614120954898685954,1614121020367577090\",\"isTop\":null,\"imgList\":[\"1614120954898685954\",\"1614121020367577090\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 12:43:42'); +INSERT INTO `sys_oper_log` VALUES (1614121865922486273, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-14 12:43:42\",\"updateBy\":null,\"updateTime\":null,\"id\":50,\"userId\":1,\"content\":\"最后一次\\\"[呲牙]\\\"成功啦\",\"images\":\"[\\\"1614120954898685954\\\",\\\"1614121020367577090\\\"]\",\"isTop\":null,\"imgList\":[\"[\\\"1614120954898685954\\\"\",\"\\\"1614121020367577090\\\"]\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 12:46:56'); +INSERT INTO `sys_oper_log` VALUES (1614122343913758722, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-14 12:43:42\",\"updateBy\":null,\"updateTime\":null,\"id\":50,\"userId\":1,\"content\":\"最后一次\\\"[呲牙]\\\"成功啦阿松大\\\"[喜欢]\\\"\",\"images\":\"1614120954898685954,1614121020367577090\",\"isTop\":null,\"imgList\":[\"1614120954898685954\",\"1614121020367577090\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 12:48:50'); +INSERT INTO `sys_oper_log` VALUES (1614122455591297025, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-14 12:43:42\",\"updateBy\":null,\"updateTime\":null,\"id\":50,\"userId\":1,\"content\":\"测试发布说说\\\"[喜欢]\\\"\",\"images\":\"1614120954898685954,1614121020367577090\",\"isTop\":null,\"imgList\":[\"1614120954898685954\",\"1614121020367577090\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 12:49:17'); +INSERT INTO `sys_oper_log` VALUES (1614123288164835329, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-13 16:37:32\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-14 12:52:35\",\"parentName\":null,\"parentId\":\"1613813815185510401\",\"children\":[],\"menuId\":\"1613816542531686400\",\"menuName\":\"说说列表\",\"orderNum\":2,\"path\":\"talks\",\"component\":\"talk/talkList/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"talk:talk:list\",\"icon\":\"tree-table\",\"remark\":\"说说管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 12:52:36'); +INSERT INTO `sys_oper_log` VALUES (1614223215855517697, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1613864916513517570\",\"articleTitle\":\"没错\",\"articleContent\":\"## 我没有错\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:29:40'); +INSERT INTO `sys_oper_log` VALUES (1614223282423316481, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1613864916513517570', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:29:56'); +INSERT INTO `sys_oper_log` VALUES (1614223342854848514, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614223342854848513\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/73304fd887f543e6bab3c13dc25818d7.jpg\",\"fileName\":\"QQ图片20210630102645.jpg\"}}', 0, '', '2023-01-14 19:30:10'); +INSERT INTO `sys_oper_log` VALUES (1614223355869773825, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1614223342854848513\",\"articleTitle\":\"没错\",\"articleContent\":\"## 我没有错\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:30:14'); +INSERT INTO `sys_oper_log` VALUES (1614223756430000129, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1614223342854848513\",\"articleTitle\":\"没错\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:31:49'); +INSERT INTO `sys_oper_log` VALUES (1614224661946679297, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1614223342854848513\",\"articleTitle\":\"没错\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:35:25'); +INSERT INTO `sys_oper_log` VALUES (1614224692464435202, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1614223342854848513\",\"articleTitle\":\"没错\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:35:32'); +INSERT INTO `sys_oper_log` VALUES (1614224828229861378, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1614223342854848513\",\"articleTitle\":\"vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:36:05'); +INSERT INTO `sys_oper_log` VALUES (1614228904174776321, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1613399733030699010', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:52:16'); +INSERT INTO `sys_oper_log` VALUES (1614228984697024515, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614228984697024514\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/3e925dbf2f3843b081c07b37d59762be.jpg\",\"fileName\":\"QQ图片20210630102619.jpg\"}}', 0, '', '2023-01-14 19:52:36'); +INSERT INTO `sys_oper_log` VALUES (1614228990703267842, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"pageName\":\"首页\",\"pageLabel\":\"home\",\"pageCover\":\"1614228984697024514\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 19:52:37'); +INSERT INTO `sys_oper_log` VALUES (1614251030088802305, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614251029958778882\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/14/00cd5ad983314d6d93b6870edc0e91b2.jpg\",\"fileName\":\"天空 云 少女 草地 唯美人物风景4k动漫壁纸3840x2160_彼岸图网.jpg\"}}', 0, '', '2023-01-14 21:20:12'); +INSERT INTO `sys_oper_log` VALUES (1614251043565101058, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":8,\"pageName\":\"留言\",\"pageLabel\":\"message\",\"pageCover\":\"1614251029958778882\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 21:20:15'); +INSERT INTO `sys_oper_log` VALUES (1614252598766972930, '留言管理', 2, 'com.zhi.blog.controller.MessageController.edit()', 'PUT', 1, 'admin', '', '/message/message', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"nickname\":\"water-之\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"messageContent\":\"测试留言\",\"ipAddress\":\"127.0.0.1\",\"ipSource\":null,\"time\":3,\"isReview\":\"Y\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 21:26:26'); +INSERT INTO `sys_oper_log` VALUES (1614253871838810113, '留言管理', 2, 'com.zhi.blog.controller.MessageController.edit()', 'PUT', 1, 'admin', '', '/message/message', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"nickname\":\"water-之\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"messageContent\":\"测试留言\",\"ipAddress\":\"127.0.0.1\",\"ipSource\":null,\"time\":1,\"isReview\":\"Y\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 21:31:29'); +INSERT INTO `sys_oper_log` VALUES (1614253924028534785, '留言管理', 2, 'com.zhi.blog.controller.MessageController.edit()', 'PUT', 1, 'admin', '', '/message/message', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"nickname\":\"water-之\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"messageContent\":\"测试留言\",\"ipAddress\":\"127.0.0.1\",\"ipSource\":null,\"time\":10,\"isReview\":\"Y\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-14 21:31:42'); +INSERT INTO `sys_oper_log` VALUES (1614508855549517825, '部门管理', 2, 'com.zhi.web.controller.system.SysDeptController.edit()', 'PUT', 1, 'admin', '', '/system/dept', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-15 14:24:41\",\"parentName\":null,\"parentId\":0,\"children\":[],\"deptId\":100,\"deptName\":\"water-之\",\"orderNum\":0,\"leader\":\"ftz\",\"phone\":\"15888888888\",\"email\":\"ftz@qq.com\",\"status\":\"0\",\"delFlag\":\"0\",\"ancestors\":\"0\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:24:42'); +INSERT INTO `sys_oper_log` VALUES (1614509080875917313, '部门管理', 1, 'com.zhi.web.controller.system.SysDeptController.add()', 'POST', 1, 'admin', '', '/system/dept', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-15 14:25:35\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-15 14:25:35\",\"parentName\":null,\"parentId\":100,\"children\":[],\"deptId\":\"1614509080808808450\",\"deptName\":\"芝士团\",\"orderNum\":1,\"leader\":\"ftz\",\"phone\":\"18888888888\",\"email\":\"2831826106@qq.com\",\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:25:36'); +INSERT INTO `sys_oper_log` VALUES (1614509199151095809, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-15 14:26:03\",\"userId\":2,\"deptId\":\"1614509080808808450\",\"userName\":\"lionli\",\"nickName\":\"疯狂的狮子Li\",\"userType\":\"sys_user\",\"email\":\"crazyLionLi@qq.com\",\"phonenumber\":\"15666666666\",\"sex\":\"1\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-05 19:54:19\",\"remark\":\"测试员\",\"dept\":{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"parentName\":null,\"parentId\":101,\"children\":[],\"deptId\":105,\"deptName\":\"测试部门\",\"orderNum\":3,\"leader\":\"若依\",\"phone\":null,\"email\":null,\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100,101\"},\"roles\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"roleId\":2,\"roleName\":\"普通角色\",\"roleKey\":\"common\",\"roleSort\":2,\"dataScope\":\"2\",\"menuCheckStrictly\":null,\"deptCheckStrictly\":null,\"status\":\"0\",\"delFlag\":null,\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":null,\"permissions\":null,\"admin\":false}],\"roleIds\":[2],\"postIds\":[2],\"roleId\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:26:04'); +INSERT INTO `sys_oper_log` VALUES (1614509251638616066, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":null,\"updateTime\":null,\"userId\":1,\"deptId\":\"1614509080808808450\",\"userName\":\"admin\",\"nickName\":\"water-之\",\"userType\":\"sys_user\",\"email\":\"2831826106@qq.com\",\"phonenumber\":\"18888888888\",\"sex\":\"0\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-15 14:23:17\",\"remark\":\"管理员\",\"dept\":{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"parentName\":null,\"parentId\":101,\"children\":[],\"deptId\":103,\"deptName\":\"研发部门\",\"orderNum\":1,\"leader\":\"若依\",\"phone\":null,\"email\":null,\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100,101\"},\"roles\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"roleId\":1,\"roleName\":\"超级管理员\",\"roleKey\":\"admin\",\"roleSort\":1,\"dataScope\":\"1\",\"menuCheckStrictly\":null,\"deptCheckStrictly\":null,\"status\":\"0\",\"delFlag\":null,\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":null,\"permissions\":null,\"admin\":true}],\"roleIds\":[1],\"postIds\":[1],\"roleId\":null,\"admin\":true}', '', 1, '不允许操作超级管理员用户', '2023-01-15 14:26:16'); +INSERT INTO `sys_oper_log` VALUES (1614509307896815617, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-15 14:26:29\",\"userId\":3,\"deptId\":\"1614509080808808450\",\"userName\":\"test\",\"nickName\":\"本部门及以下 密码666666\",\"userType\":\"sys_user\",\"email\":\"\",\"phonenumber\":\"\",\"sex\":\"0\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-05 19:54:34\",\"remark\":null,\"dept\":{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"parentName\":null,\"parentId\":102,\"children\":[],\"deptId\":108,\"deptName\":\"市场部门\",\"orderNum\":1,\"leader\":\"若依\",\"phone\":null,\"email\":null,\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100,102\"},\"roles\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"roleId\":3,\"roleName\":\"本部门及以下\",\"roleKey\":\"test1\",\"roleSort\":3,\"dataScope\":\"4\",\"menuCheckStrictly\":null,\"deptCheckStrictly\":null,\"status\":\"0\",\"delFlag\":null,\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":null,\"permissions\":null,\"admin\":false}],\"roleIds\":[3],\"postIds\":[],\"roleId\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:26:30'); +INSERT INTO `sys_oper_log` VALUES (1614509339702222850, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-01-15 14:26:37\",\"userId\":4,\"deptId\":\"1614509080808808450\",\"userName\":\"test1\",\"nickName\":\"仅本人 密码666666\",\"userType\":\"sys_user\",\"email\":\"\",\"phonenumber\":\"\",\"sex\":\"0\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-05 19:54:34\",\"remark\":null,\"dept\":{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"parentName\":null,\"parentId\":100,\"children\":[],\"deptId\":102,\"deptName\":\"长沙分公司\",\"orderNum\":2,\"leader\":\"若依\",\"phone\":null,\"email\":null,\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100\"},\"roles\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"roleId\":4,\"roleName\":\"仅本人\",\"roleKey\":\"test2\",\"roleSort\":4,\"dataScope\":\"5\",\"menuCheckStrictly\":null,\"deptCheckStrictly\":null,\"status\":\"0\",\"delFlag\":null,\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":null,\"permissions\":null,\"admin\":false}],\"roleIds\":[4],\"postIds\":[],\"roleId\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:26:37'); +INSERT INTO `sys_oper_log` VALUES (1614509616127827970, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/109', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:43'); +INSERT INTO `sys_oper_log` VALUES (1614509626651336705, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/108', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:46'); +INSERT INTO `sys_oper_log` VALUES (1614509635832668162, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/102', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:48'); +INSERT INTO `sys_oper_log` VALUES (1614509646523949057, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/107', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:51'); +INSERT INTO `sys_oper_log` VALUES (1614509654157582337, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/106', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:52'); +INSERT INTO `sys_oper_log` VALUES (1614509662504247298, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/105', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:54'); +INSERT INTO `sys_oper_log` VALUES (1614509671542972417, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/104', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:27:57'); +INSERT INTO `sys_oper_log` VALUES (1614509681567358978, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/103', '127.0.0.1', '内网IP', '{}', '{\"code\":601,\"msg\":\"部门存在用户,不允许删除\",\"data\":null}', 0, '', '2023-01-15 14:27:59'); +INSERT INTO `sys_oper_log` VALUES (1614510113987518465, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/103', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:29:42'); +INSERT INTO `sys_oper_log` VALUES (1614510125370859522, '部门管理', 3, 'com.zhi.web.controller.system.SysDeptController.remove()', 'DELETE', 1, 'admin', '', '/system/dept/101', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 14:29:45'); +INSERT INTO `sys_oper_log` VALUES (1614553932061749249, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.changeStatus()', 'PUT', 1, 'admin', '', '/system/user/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-01-15 17:23:49\",\"userId\":\"1614548379499507713\",\"deptId\":null,\"userName\":null,\"nickName\":null,\"userType\":null,\"email\":null,\"phonenumber\":null,\"sex\":null,\"avatar\":null,\"status\":\"1\",\"delFlag\":null,\"loginIp\":null,\"loginDate\":null,\"remark\":null,\"dept\":null,\"roles\":null,\"roleIds\":null,\"postIds\":null,\"roleId\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 17:23:49'); +INSERT INTO `sys_oper_log` VALUES (1614605745679081474, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1614228984697024514', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:49:42'); +INSERT INTO `sys_oper_log` VALUES (1614606003926573058, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606003863658498\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/40d34efc34c04b60baff7449036d57cf.jpg\",\"fileName\":\"高山湖泊风景3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:50:44'); +INSERT INTO `sys_oper_log` VALUES (1614606010968809474, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"pageName\":\"首页\",\"pageLabel\":\"home\",\"pageCover\":\"1614606003863658498\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:50:46'); +INSERT INTO `sys_oper_log` VALUES (1614606077901512705, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606077834403841\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/b28c9780398444b29ca0efdbdac07c67.jpg\",\"fileName\":\"芬兰,芬兰,夕阳3440x1440风景壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:51:02'); +INSERT INTO `sys_oper_log` VALUES (1614606083962281986, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":2,\"pageName\":\"归档\",\"pageLabel\":\"archive\",\"pageCover\":\"1614606077834403841\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:51:03'); +INSERT INTO `sys_oper_log` VALUES (1614606235695423490, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606235632508930\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/a7228927d57245e990d57f43a9029ba4.jpg\",\"fileName\":\"荷兰盛开的石南3440x1440带鱼屏壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:51:39'); +INSERT INTO `sys_oper_log` VALUES (1614606247250731009, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":3,\"pageName\":\"分类\",\"pageLabel\":\"category\",\"pageCover\":\"1614606235632508930\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:51:42'); +INSERT INTO `sys_oper_log` VALUES (1614606349734354945, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606349667246081\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/b4f2141bc9974b2eaca0992e7b78e31c.jpg\",\"fileName\":\"美丽的海边风景3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:52:06'); +INSERT INTO `sys_oper_log` VALUES (1614606358714359810, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":4,\"pageName\":\"标签\",\"pageLabel\":\"tag\",\"pageCover\":\"1614606349667246081\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:52:09'); +INSERT INTO `sys_oper_log` VALUES (1614606431695249410, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606431695249409\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/fb76b85f778a4e6bae364ba1bcd8c492.jpg\",\"fileName\":\"夜海 少女 3440x1440动漫壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:52:26'); +INSERT INTO `sys_oper_log` VALUES (1614606446241095682, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":9,\"pageName\":\"个人中心\",\"pageLabel\":\"user\",\"pageCover\":\"1614606431695249409\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:52:29'); +INSERT INTO `sys_oper_log` VALUES (1614606523919605762, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606523919605761\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/1845ae60b1c04ee18d10e7e27454c035.jpg\",\"fileName\":\"俄勒冈州,太平洋城,岩石,海边风景4K壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:52:48'); +INSERT INTO `sys_oper_log` VALUES (1614606544803045377, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":10,\"pageName\":\"文章列表\",\"pageLabel\":\"articleList\",\"pageCover\":\"1614606523919605761\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:52:53'); +INSERT INTO `sys_oper_log` VALUES (1614606607352700930, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614606607352700929\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/e5a7b176d64a445e9b665ab1a40f2fec.jpg\",\"fileName\":\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:53:08'); +INSERT INTO `sys_oper_log` VALUES (1614606626952683521, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":6,\"pageName\":\"友链\",\"pageLabel\":\"link\",\"pageCover\":\"1614606607352700929\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:53:12'); +INSERT INTO `sys_oper_log` VALUES (1614607161852272641, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614607161785163778\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/e218c7845b8c4d59b82a400201896204.jpg\",\"fileName\":\"俄勒冈州,太平洋城,岩石,海边风景4K壁纸_千叶网.jpg\"}}', 0, '', '2023-01-15 20:55:20'); +INSERT INTO `sys_oper_log` VALUES (1614607169267802114, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":11,\"pageName\":\"说说\",\"pageLabel\":\"talk\",\"pageCover\":\"1614607161785163778\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 20:55:22'); +INSERT INTO `sys_oper_log` VALUES (1614610914072334337, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614610913900367873\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/15/56fdb73fae684261b93ca2d184906bd3.jpg\",\"fileName\":\"美丽蓝色花瓣3440x1440_千叶网.jpg\"}}', 0, '', '2023-01-15 21:10:15'); +INSERT INTO `sys_oper_log` VALUES (1614610921215234050, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":7,\"pageName\":\"关于\",\"pageLabel\":\"about\",\"pageCover\":\"1614610913900367873\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-15 21:10:16'); +INSERT INTO `sys_oper_log` VALUES (1614870127927488513, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1614223342854848513', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-16 14:20:16'); +INSERT INTO `sys_oper_log` VALUES (1614870206906232833, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614870206843318273\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/16/736a20a9c0d14c9bb33488936599d041.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-01-16 14:20:35'); +INSERT INTO `sys_oper_log` VALUES (1614870273054601217, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\",\"测试\"],\"articleCover\":\"1614870206843318273\",\"articleTitle\":\"新的vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-16 14:20:51'); +INSERT INTO `sys_oper_log` VALUES (1614870928829837313, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1614120954898685954', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-16 14:23:27'); +INSERT INTO `sys_oper_log` VALUES (1614870976867201026, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1614870976800092162\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/16/80c7f49646ed4be7a706b654f85ccfa2.jpg\",\"fileName\":\"古墓丽影_暗影3440x1440带鱼屏壁纸_千叶网.jpg\"}}', 0, '', '2023-01-16 14:23:38'); +INSERT INTO `sys_oper_log` VALUES (1614871010631348226, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-14 12:43:42\",\"updateBy\":null,\"updateTime\":null,\"id\":50,\"userId\":1,\"content\":\"测试发布说说\\\"[喜欢]\\\"\\\"[调皮]\\\"\\\"[打call]\\\"\",\"images\":\"1614121020367577090,1614870976800092162\",\"isTop\":null,\"imgList\":[\"1614121020367577090\",\"1614870976800092162\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-16 14:23:46'); +INSERT INTO `sys_oper_log` VALUES (1614988100012924929, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1506', '127.0.0.1', '内网IP', '{}', '{\"code\":601,\"msg\":\"存在子菜单,不允许删除\",\"data\":null}', 0, '', '2023-01-16 22:09:03'); +INSERT INTO `sys_oper_log` VALUES (1614988124826427394, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1511', '127.0.0.1', '内网IP', '{}', '{\"code\":601,\"msg\":\"菜单已分配,不允许删除\",\"data\":null}', 0, '', '2023-01-16 22:09:09'); +INSERT INTO `sys_oper_log` VALUES (1615211813593538561, '评论管理', 3, 'com.zhi.blog.controller.CommentController.remove()', 'DELETE', 1, 'admin', '', '/comment/comment/1614588562538348547', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-17 12:58:00'); +INSERT INTO `sys_oper_log` VALUES (1615211838843248642, '评论管理', 3, 'com.zhi.blog.controller.CommentController.remove()', 'DELETE', 1, 'admin', '', '/comment/comment/1614588562538348548', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-17 12:58:06'); +INSERT INTO `sys_oper_log` VALUES (1615211859709911041, '评论管理', 3, 'com.zhi.blog.controller.CommentController.remove()', 'DELETE', 1, 'admin', '', '/comment/comment/5', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-17 12:58:11'); +INSERT INTO `sys_oper_log` VALUES (1615213249089826817, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"付费\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1612781375180632066\",\"articleTitle\":\"测试文章\",\"articleContent\":\"这一次我一定要成功\",\"type\":1,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":2}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-01-17 13:03:42'); +INSERT INTO `sys_oper_log` VALUES (1623662249392492546, '评论管理', 3, 'com.zhi.blog.controller.CommentController.remove()', 'DELETE', 1, 'admin', '', '/comment/comment/1614583947344216065,1614584340719599618,1614586639571599361', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-09 20:37:01'); +INSERT INTO `sys_oper_log` VALUES (1624274517046194177, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"老妈\",\"createTime\":\"2023-01-15 17:01:45\",\"updateBy\":null,\"updateTime\":null,\"userId\":5,\"deptId\":null,\"userName\":\"荷塘\",\"nickName\":\"荷塘\",\"userType\":\"sys_user\",\"email\":\"2831826106@qq.com\",\"phonenumber\":\"\",\"sex\":\"0\",\"avatar\":\"https://s1.ax1x.com/2023/01/15/pSQf91A.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-19 23:00:18\",\"remark\":null,\"intro\":null,\"webSite\":null,\"dept\":null,\"roles\":[],\"roleIds\":[4],\"postIds\":[],\"roleId\":null,\"admin\":false}', '{\"code\":500,\"msg\":\"修改用户\'荷塘\'失败,邮箱账号已存在\",\"data\":null}', 0, '', '2023-02-11 13:09:57'); +INSERT INTO `sys_oper_log` VALUES (1624274534045708290, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"老妈\",\"createTime\":\"2023-01-15 17:01:45\",\"updateBy\":null,\"updateTime\":null,\"userId\":5,\"deptId\":null,\"userName\":\"荷塘\",\"nickName\":\"荷塘\",\"userType\":\"sys_user\",\"email\":\"2831826106@qq.com\",\"phonenumber\":\"\",\"sex\":\"0\",\"avatar\":\"https://s1.ax1x.com/2023/01/15/pSQf91A.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-19 23:00:18\",\"remark\":null,\"intro\":null,\"webSite\":null,\"dept\":null,\"roles\":[],\"roleIds\":[4],\"postIds\":[],\"roleId\":null,\"admin\":false}', '{\"code\":500,\"msg\":\"修改用户\'荷塘\'失败,邮箱账号已存在\",\"data\":null}', 0, '', '2023-02-11 13:10:01'); +INSERT INTO `sys_oper_log` VALUES (1624274642627850242, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '127.0.0.1', '内网IP', '{\"createBy\":\"kalashok-pan\",\"createTime\":\"2023-01-21 14:10:29\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-11 13:10:27\",\"userId\":\"1614548939325845510\",\"deptId\":null,\"userName\":\"kalashok-pan\",\"nickName\":\"卡拉肖克-潘\",\"userType\":\"sys_user\",\"email\":\"\",\"phonenumber\":\"\",\"sex\":\"0\",\"avatar\":\"https://foruda.gitee.com/avatar/1673853732714613266/8669563_kalashok-pan_1673853732.png\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"127.0.0.1\",\"loginDate\":\"2023-01-21 22:14:36\",\"remark\":\"暂无\",\"intro\":null,\"webSite\":null,\"dept\":null,\"roles\":[],\"roleIds\":[4],\"postIds\":[],\"roleId\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 13:10:27'); +INSERT INTO `sys_oper_log` VALUES (1624274822630600706, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.edit()', 'PUT', 1, 'admin', '', '/system/role', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-11 13:11:09\",\"roleId\":4,\"roleName\":\"仅本人\",\"roleKey\":\"test2\",\"roleSort\":4,\"dataScope\":\"5\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":null,\"flag\":false,\"menuIds\":[\"1610972802922405889\",\"1610973263779946497\",\"1611336461808898048\",\"1611336461808898049\",\"1611336461808898050\",\"1611336461808898051\",\"1611336461808898052\",\"1611336461808898053\",\"1611613727679938560\",\"1611613727679938561\",\"1611613727679938562\",\"1611613727679938563\",\"1611613727679938564\",\"1611613727679938565\",\"1611975928588574720\",\"1611975928588574721\",\"1611975928588574722\",\"1611975928588574723\",\"1611975928588574724\",\"1611975928588574725\",5,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511],\"deptIds\":null,\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 13:11:10'); +INSERT INTO `sys_oper_log` VALUES (1624281077399023617, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.edit()', 'PUT', 1, 'admin', '', '/system/role', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-11 13:36:01\",\"roleId\":4,\"roleName\":\"仅本人\",\"roleKey\":\"test2\",\"roleSort\":4,\"dataScope\":\"5\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":null,\"flag\":false,\"menuIds\":[\"1610972802922405889\",\"1610973263779946497\",\"1611336461808898048\",\"1611336461808898049\",\"1611336461808898050\",\"1611336461808898051\",\"1611336461808898052\",\"1611336461808898053\",\"1611613727679938560\",\"1611613727679938561\",\"1611613727679938562\",\"1611613727679938563\",\"1611613727679938564\",\"1611613727679938565\",\"1611975928588574720\",\"1611975928588574721\",\"1611975928588574722\",\"1611975928588574723\",\"1611975928588574724\",\"1611975928588574725\",1,100,1001,1002,1003,1004,1005,1006,1007,101,1008,1009,1010,1011,1012,102,1013,1014,1015,1016,103,1017,1018,1019,1020,104,1021,1022,1023,1024,1025,105,1026,1027,1028,1029,1030,106,1031,1032,1033,1034,1035,107,1036,1037,1038,1039,108,500,1040,1041,1042,501,1043,1044,1045,1050,118,1600,1601,1602,1603,1604,1605,5,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511],\"deptIds\":null,\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 13:36:01'); +INSERT INTO `sys_oper_log` VALUES (1624290470186201090, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.dataScope()', 'PUT', 1, 'admin', '', '/system/role/dataScope', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-11 14:13:20\",\"roleId\":4,\"roleName\":\"仅本人\",\"roleKey\":\"test2\",\"roleSort\":4,\"dataScope\":\"5\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":[],\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 14:13:21'); +INSERT INTO `sys_oper_log` VALUES (1624293141957849089, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'test1', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1614870206843318273\",\"articleTitle\":\"新的vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 14:23:58'); +INSERT INTO `sys_oper_log` VALUES (1624311868313059329, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'test1', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1624311868237561857\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/02/11/f270e45538104ebb951f9b4584480021.png\",\"fileName\":\"logo.png\"}}', 0, '', '2023-02-11 15:38:22'); +INSERT INTO `sys_oper_log` VALUES (1624311874814230530, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'test1', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"test1\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":144,\"userId\":4,\"categoryId\":225,\"categoryName\":\"\",\"tagNameList\":[],\"articleCover\":\"1624311868237561857\",\"articleTitle\":\"test1的文章\",\"articleContent\":\"test1的文章\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 15:38:24'); +INSERT INTO `sys_oper_log` VALUES (1624311932792094721, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'test1', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":144,\"userId\":4,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1624311868237561857\",\"articleTitle\":\"test1的文章\",\"articleContent\":\"test1的文章\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-11 15:38:38'); +INSERT INTO `sys_oper_log` VALUES (1625478372123475970, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625478371997646850\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/02/14/755f9aff4a644dcab2084a39ed1feb25.png\",\"fileName\":\"XHIZI6T41671292212659.png\"}}', 0, '', '2023-02-14 20:53:38'); +INSERT INTO `sys_oper_log` VALUES (1625478381686489090, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":145,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1625478371997646850\",\"articleTitle\":\"测试\",\"articleContent\":\"测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 20:53:41'); +INSERT INTO `sys_oper_log` VALUES (1625480098423504898, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625480098360590337\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/02/14/3eb4a158cb6640cd840f6faad0d3fbb9.png\",\"fileName\":\"XHIZI6T41671292212659.png\"}}', 0, '', '2023-02-14 21:00:30'); +INSERT INTO `sys_oper_log` VALUES (1625487055830122498, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":146,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1625480098360590337\",\"articleTitle\":\"11\",\"articleContent\":\"11\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 21:28:09'); +INSERT INTO `sys_oper_log` VALUES (1625487737119313922, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/146', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 21:30:51'); +INSERT INTO `sys_oper_log` VALUES (1625487743901503489, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/145', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 21:30:53'); +INSERT INTO `sys_oper_log` VALUES (1625487802793725953, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625487802730811393\",\"url\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/02/14/01f9bf2767854ac08f914b612e9b0b7f.png\",\"fileName\":\"XHIZI6T41671292212659.png\"}}', 0, '', '2023-02-14 21:31:07'); +INSERT INTO `sys_oper_log` VALUES (1625487811501101058, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1625487802730811393\",\"articleTitle\":\"1\",\"articleContent\":\"1\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-02-14 21:31:09'); +INSERT INTO `sys_oper_log` VALUES (1625487838730522626, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1625487802730811393\",\"articleTitle\":\"1\",\"articleContent\":\"1\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-02-14 21:31:16'); +INSERT INTO `sys_oper_log` VALUES (1625488008918601729, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":null,\"categoryId\":null,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1625487802730811393\",\"articleTitle\":\"1\",\"articleContent\":\"1\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, 'For input string: \"sys_user:1\"', '2023-02-14 21:31:56'); +INSERT INTO `sys_oper_log` VALUES (1625488897154756610, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":147,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1625487802730811393\",\"articleTitle\":\"1\",\"articleContent\":\"1\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 21:35:28'); +INSERT INTO `sys_oper_log` VALUES (1625489375234138114, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":148,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1625487802730811393\",\"articleTitle\":\"1\",\"articleContent\":\"1\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 21:37:22'); +INSERT INTO `sys_oper_log` VALUES (1625490298421420033, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":149,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"html\"],\"articleCover\":\"1625487802730811393\",\"articleTitle\":\"1\",\"articleContent\":\"1\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 21:41:02'); +INSERT INTO `sys_oper_log` VALUES (1625495355380506626, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-14 22:01:07\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:01:07\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1625495355317592066\",\"menuName\":\"云端配置\",\"orderNum\":10,\"path\":\"oss-config/index\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"download\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:01:08'); +INSERT INTO `sys_oper_log` VALUES (1625495551623602177, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-14 22:01:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:01:54\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1625495355317592066\",\"menuName\":\"云端配置\",\"orderNum\":10,\"path\":\"system/oss-config/index\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"download\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:01:54'); +INSERT INTO `sys_oper_log` VALUES (1625495738651811841, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-14 22:01:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:02:38\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1625495355317592066\",\"menuName\":\"云端配置\",\"orderNum\":5,\"path\":\"system/oss-config/index\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"download\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:02:39'); +INSERT INTO `sys_oper_log` VALUES (1625495844050477057, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-14 22:01:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:03:04\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1625495355317592066\",\"menuName\":\"云端配置\",\"orderNum\":4,\"path\":\"system/oss-config/index\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"download\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:03:04'); +INSERT INTO `sys_oper_log` VALUES (1625495864619343873, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:03:09\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":2,\"menuName\":\"系统监控\",\"orderNum\":5,\"path\":\"monitor\",\"component\":null,\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"\",\"icon\":\"monitor\",\"remark\":\"系统监控目录\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:03:09'); +INSERT INTO `sys_oper_log` VALUES (1625495981514596354, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:03:36\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":1,\"menuName\":\"系统管理\",\"orderNum\":5,\"path\":\"system\",\"component\":null,\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"\",\"icon\":\"system\",\"remark\":\"系统管理目录\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:03:37'); +INSERT INTO `sys_oper_log` VALUES (1625496082559574018, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-14 22:01:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-14 22:04:00\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1625495355317592066\",\"menuName\":\"云端配置\",\"orderNum\":4,\"path\":\"system/oss-config/index\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"upload\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-14 22:04:01'); +INSERT INTO `sys_oper_log` VALUES (1625778064375959553, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/149', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 16:44:31'); +INSERT INTO `sys_oper_log` VALUES (1625778069941800961, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/148', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 16:44:32'); +INSERT INTO `sys_oper_log` VALUES (1625778076593967105, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/147', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 16:44:34'); +INSERT INTO `sys_oper_log` VALUES (1625778085594943489, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/144', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 16:44:36'); +INSERT INTO `sys_oper_log` VALUES (1625787279983267841, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":\"hBaUeH9xKIj6dgvqFPCXHdk3wcoAavN2\",\"secretKey\":\"hBaUeH9xKIj6dgvqFPCXHdk3wcoAavN2\",\"bucketName\":\"blog\",\"prefix\":\"\",\"endpoint\":\"127.0.0.1:9000\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"1\",\"region\":\"\",\"ext1\":\"\",\"remark\":\"\",\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 17:21:08'); +INSERT INTO `sys_oper_log` VALUES (1625787307225272321, '对象存储状态修改', 2, 'com.zhi.web.controller.system.SysOssConfigController.changeStatus()', 'PUT', 1, 'admin', '', '/system/oss/config/changeStatus', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":null,\"secretKey\":null,\"bucketName\":null,\"prefix\":null,\"endpoint\":null,\"domain\":null,\"isHttps\":null,\"status\":\"0\",\"region\":null,\"ext1\":null,\"remark\":null,\"accessPolicy\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 17:21:14'); +INSERT INTO `sys_oper_log` VALUES (1625787348908265474, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[The Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 1743F5041BDC54A0; S3 Extended Request ID: 51b06bbe-5c82-4e94-8731-642a4083de7e; Proxy: null)]', '2023-02-15 17:21:24'); +INSERT INTO `sys_oper_log` VALUES (1625787606790852610, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[The Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 1743F5126CA97120; S3 Extended Request ID: 51b06bbe-5c82-4e94-8731-642a4083de7e; Proxy: null)]', '2023-02-15 17:22:26'); +INSERT INTO `sys_oper_log` VALUES (1625787904087314434, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":\"Di4h8evEEG9p9fsB\",\"secretKey\":\"hBaUeH9xKIj6dgvqFPCXHdk3wcoAavN2\",\"bucketName\":\"blog\",\"prefix\":\"\",\"endpoint\":\"127.0.0.1:9000\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"0\",\"region\":\"\",\"ext1\":\"\",\"remark\":\"\",\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 17:23:37'); +INSERT INTO `sys_oper_log` VALUES (1625787929773232130, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625787929773232129\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/15/c33f0514eddf4d1cae8a3e114a54c1af.png\",\"fileName\":\"1.png\"}}', 0, '', '2023-02-15 17:23:43'); +INSERT INTO `sys_oper_log` VALUES (1625788426961833986, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625788426961833985\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/15/8f08966dff5c4f21861f997453d23cda.jpg\",\"fileName\":\"奔驰银箭MercedesBenz Vision EQ Silver Arrow 3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-15 17:25:41'); +INSERT INTO `sys_oper_log` VALUES (1625788430799622145, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"付费\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1625788426961833985\",\"articleTitle\":\"测试文章\",\"articleContent\":\"这一次我一定要成功\",\"type\":1,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 17:25:42'); +INSERT INTO `sys_oper_log` VALUES (1625844324862369793, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/225', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:07:48'); +INSERT INTO `sys_oper_log` VALUES (1625844424464506881, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/53', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:08:12'); +INSERT INTO `sys_oper_log` VALUES (1625844436040785922, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/51', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:08:15'); +INSERT INTO `sys_oper_log` VALUES (1625844453824634882, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/50', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:08:19'); +INSERT INTO `sys_oper_log` VALUES (1625845605282729985, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[Unable to execute HTTP request: Connect to 127.0.0.1:9000 [/127.0.0.1] failed: Connection refused: connect]', '2023-02-15 21:12:54'); +INSERT INTO `sys_oper_log` VALUES (1625845998343540739, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625845998343540738\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/15/bf09b6dafe91486ab42c70e3674bb84b.jpg\",\"fileName\":\"1.jpg\"}}', 0, '', '2023-02-15 21:14:27'); +INSERT INTO `sys_oper_log` VALUES (1625846030375440386, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":150,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1625845998343540738\",\"articleTitle\":\"123\",\"articleContent\":\"123\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:14:35'); +INSERT INTO `sys_oper_log` VALUES (1625846305064603649, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'test1', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625846305001689090\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/15/c152c56a1200477f85e9d6e8364d9f13.jpg\",\"fileName\":\"QQ图片20210630102645.jpg\"}}', 0, '', '2023-02-15 21:15:41'); +INSERT INTO `sys_oper_log` VALUES (1625846327227305985, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'test1', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"test1\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":151,\"userId\":4,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1625846305001689090\",\"articleTitle\":\"11111\",\"articleContent\":\"11111\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:15:46'); +INSERT INTO `sys_oper_log` VALUES (1625847073033277442, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'test1', '', '/article/article/151', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:18:44'); +INSERT INTO `sys_oper_log` VALUES (1625847185734225921, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1625788426961833985', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:19:11'); +INSERT INTO `sys_oper_log` VALUES (1625847195834109954, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1625847195834109953\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/15/d1003aa894b3458ab595e3b00b171d48.jpg\",\"fileName\":\"1.jpg\"}}', 0, '', '2023-02-15 21:19:13'); +INSERT INTO `sys_oper_log` VALUES (1625847199101472769, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":138,\"userId\":1,\"categoryId\":217,\"categoryName\":\"付费\",\"tagNameList\":[\"springboot\",\"vue\"],\"articleCover\":\"1625847195834109953\",\"articleTitle\":\"测试文章\",\"articleContent\":\"这一次我一定要成功\",\"type\":1,\"originalUrl\":\"1\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:19:14'); +INSERT INTO `sys_oper_log` VALUES (1625847218852450305, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/138', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-15 21:19:18'); +INSERT INTO `sys_oper_log` VALUES (1626093282092146690, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1626093282025037825\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/16/f73c9860389842e590cecab5be49a3b3.jpg\",\"fileName\":\"宇宙.jpg\"}}', 0, '', '2023-02-16 13:37:04'); +INSERT INTO `sys_oper_log` VALUES (1626093305089515522, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":152,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1626093282025037825\",\"articleTitle\":\"123\",\"articleContent\":\"123\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":2}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:37:10'); +INSERT INTO `sys_oper_log` VALUES (1626093921014669314, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/152', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:39:37'); +INSERT INTO `sys_oper_log` VALUES (1626094020730052609, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/56', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:40:01'); +INSERT INTO `sys_oper_log` VALUES (1626094366458142721, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1626094366391033858\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/16/02df055e87e049ae9af540e380b39766.jpg\",\"fileName\":\"QQ图片20210630102658.jpg\"}}', 0, '', '2023-02-16 13:41:23'); +INSERT INTO `sys_oper_log` VALUES (1626094375538810881, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"userId\":1,\"categoryId\":null,\"categoryName\":null,\"tagNameList\":[],\"articleCover\":\"1626094366391033858\",\"articleTitle\":\"CESHI\",\"articleContent\":\"CESHI\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-02-16 13:41:25'); +INSERT INTO `sys_oper_log` VALUES (1626094642476900353, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":226,\"categoryName\":\"默认\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:42:29'); +INSERT INTO `sys_oper_log` VALUES (1626094686273822721, '标签管理', 1, 'com.zhi.blog.controller.TagController.add()', 'POST', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":67,\"tagName\":\"默认\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:42:39'); +INSERT INTO `sys_oper_log` VALUES (1626098067285487618, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1626098067067383809\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/16/80992e0e2ac9492cb6d6c5800b9ea3fe.jpg\",\"fileName\":\"QQ图片20210630104247.jpg\"}}', 0, '', '2023-02-16 13:56:05'); +INSERT INTO `sys_oper_log` VALUES (1626098077410537474, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":153,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1626098067067383809\",\"articleTitle\":\"123\",\"articleContent\":\"123\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":2}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:56:08'); +INSERT INTO `sys_oper_log` VALUES (1626098177729900546, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/150', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 13:56:32'); +INSERT INTO `sys_oper_log` VALUES (1626100461083873282, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/1', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:05:36'); +INSERT INTO `sys_oper_log` VALUES (1626101052115886082, '分类管理', 1, 'com.zhi.blog.controller.CategoryController.add()', 'POST', 1, 'admin', '', '/category/category', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":227,\"categoryName\":\"默认\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:07:57'); +INSERT INTO `sys_oper_log` VALUES (1626101128309612545, '分类管理', 3, 'com.zhi.blog.controller.CategoryController.remove()', 'DELETE', 1, 'admin', '', '/category/category/1', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"不允许删除默认分类\",\"data\":null}', 0, '', '2023-02-16 14:08:15'); +INSERT INTO `sys_oper_log` VALUES (1626101164233826306, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/1', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"不允许删除默认标签\",\"data\":null}', 0, '', '2023-02-16 14:08:24'); +INSERT INTO `sys_oper_log` VALUES (1626101207946862593, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/1', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"不允许删除默认标签\",\"data\":null}', 0, '', '2023-02-16 14:08:34'); +INSERT INTO `sys_oper_log` VALUES (1626101318445801474, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/1,66', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"不允许删除默认标签\",\"data\":null}', 0, '', '2023-02-16 14:09:00'); +INSERT INTO `sys_oper_log` VALUES (1626101728887808002, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/66', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"已有文章对应此标签,无法删除\",\"data\":null}', 0, '', '2023-02-16 14:10:38'); +INSERT INTO `sys_oper_log` VALUES (1626102097579712513, '标签管理', 3, 'com.zhi.blog.controller.TagController.remove()', 'DELETE', 1, 'admin', '', '/tag/tag/1', '127.0.0.1', '内网IP', '{}', '{\"code\":500,\"msg\":\"不允许删除默认标签\",\"data\":null}', 0, '', '2023-02-16 14:12:06'); +INSERT INTO `sys_oper_log` VALUES (1626102236230819841, '标签管理', 2, 'com.zhi.blog.controller.TagController.edit()', 'PUT', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"tagName\":\"默认1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:12:39'); +INSERT INTO `sys_oper_log` VALUES (1626102251271593986, '标签管理', 2, 'com.zhi.blog.controller.TagController.edit()', 'PUT', 1, 'admin', '', '/tag/tag', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"tagName\":\"默认\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:12:43'); +INSERT INTO `sys_oper_log` VALUES (1626103128623521794, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/57', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:16:12'); +INSERT INTO `sys_oper_log` VALUES (1626104291028738050, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1626104290965823489\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/16/9f00764fa98545a0a9745af49611d6df.jpg\",\"fileName\":\"宇宙.jpg\"}}', 0, '', '2023-02-16 14:20:49'); +INSERT INTO `sys_oper_log` VALUES (1626104299861942273, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-15 21:08:07\",\"updateBy\":null,\"updateTime\":null,\"id\":55,\"userId\":1,\"content\":\"123\",\"images\":\"1626104290965823489\",\"isTop\":null,\"imgList\":[\"1626104290965823489\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'55\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/TalkMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.TalkMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_talk ( id, user_id, content, images, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'55\' for key \'PRIMARY\'\n; Duplicate entry \'55\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'55\' for key \'PRIMARY\'', '2023-02-16 14:20:51'); +INSERT INTO `sys_oper_log` VALUES (1626104340341170177, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":58,\"userId\":1,\"content\":\"123\",\"images\":null,\"isTop\":null,\"imgList\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:21:01'); +INSERT INTO `sys_oper_log` VALUES (1626104363510505473, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/58', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:21:06'); +INSERT INTO `sys_oper_log` VALUES (1626104384729489410, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1626104384729489409\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/16/aee9e25c646640198a1ebe91ebfd558a.jpg\",\"fileName\":\"宇宙.jpg\"}}', 0, '', '2023-02-16 14:21:12'); +INSERT INTO `sys_oper_log` VALUES (1626104390031089665, '说说管理', 1, 'com.zhi.blog.controller.TalkController.add()', 'POST', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":59,\"userId\":1,\"content\":\"123\",\"images\":\"1626104384729489409\",\"isTop\":null,\"imgList\":[\"1626104384729489409\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:21:13'); +INSERT INTO `sys_oper_log` VALUES (1626104443470716929, '说说管理', 2, 'com.zhi.blog.controller.TalkController.edit()', 'PUT', 1, 'admin', '', '/talk/talk', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-16 14:21:13\",\"updateBy\":null,\"updateTime\":null,\"id\":59,\"userId\":1,\"content\":\"123666\",\"images\":\"1626104384729489409\",\"isTop\":null,\"imgList\":[\"1626104384729489409\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-16 14:21:26'); +INSERT INTO `sys_oper_log` VALUES (1627233397812326401, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-19 17:07:28\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-19 17:07:28\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1627233395924889602\",\"menuName\":\"关于我\",\"orderNum\":4,\"path\":\"about/About.vue\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"people\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-19 17:07:29'); +INSERT INTO `sys_oper_log` VALUES (1627233573985677314, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-19 17:07:29\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-19 17:08:10\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1627233395924889602\",\"menuName\":\"关于我\",\"orderNum\":4,\"path\":\"about\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"people\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-19 17:08:11'); +INSERT INTO `sys_oper_log` VALUES (1627234047824588801, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-19 17:07:29\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-19 17:10:03\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1627233395924889602\",\"menuName\":\"关于我\",\"orderNum\":4,\"path\":\"about\",\"component\":\"about\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"theme\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-19 17:10:04'); +INSERT INTO `sys_oper_log` VALUES (1627234242603872258, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-19 17:07:29\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-19 17:10:50\",\"parentName\":null,\"parentId\":\"1613139021339353090\",\"children\":[],\"menuId\":\"1627233395924889602\",\"menuName\":\"关于我\",\"orderNum\":4,\"path\":\"about\",\"component\":\"about/About.vue\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"theme\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-19 17:10:51'); +INSERT INTO `sys_oper_log` VALUES (1627502180934127617, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627502179105411073\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/8fd16de1a8554a7d9390d0f72a696dfe.jpg\",\"fileName\":\"QQ图片20210630123438.jpg\"}}', 0, '', '2023-02-20 10:55:32'); +INSERT INTO `sys_oper_log` VALUES (1627503991862628353, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627503990038106114\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/e8965b9e67fc4620afb5b6164b8252ad.jpg\",\"fileName\":\"QQ图片20210630123438.jpg\"}}', 0, '', '2023-02-20 11:02:44'); +INSERT INTO `sys_oper_log` VALUES (1627504234058518530, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627504232301105154\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/613d1c41c1e4440197404428a479d34e.jpg\",\"fileName\":\"bg.jpg\"}}', 0, '', '2023-02-20 11:03:42'); +INSERT INTO `sys_oper_log` VALUES (1627504613349429250, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627504611596210178\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/f053bc30eb244bd8881d07ae09f24514.jpg\",\"fileName\":\"QQ图片20210630104301.jpg\"}}', 0, '', '2023-02-20 11:05:12'); +INSERT INTO `sys_oper_log` VALUES (1627511141108322305, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627511139413823490\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/cf788d70c46a440d8ed34ed775086b89.jpg\",\"fileName\":\"QQ图片20210630123438.jpg\"}}', 0, '', '2023-02-20 11:31:08'); +INSERT INTO `sys_oper_log` VALUES (1627511357404385281, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627511333031284737\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/4467f549139a4833b281fe83ab0a9fcc.jpeg\",\"fileName\":\"digitalart,城市,未来,猫,fantasyart,科幻_千叶网.jpeg\"}}', 0, '', '2023-02-20 11:32:00'); +INSERT INTO `sys_oper_log` VALUES (1627511452283736066, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627511450526322690\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/e5ab0134bf1644ea88e4095323356b05.jpeg\",\"fileName\":\"digitalart,城市,未来,猫,fantasyart,科幻_千叶网.jpeg\"}}', 0, '', '2023-02-20 11:32:23'); +INSERT INTO `sys_oper_log` VALUES (1627511566293307394, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627511565311840258\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/e7a1c90ebad94a82bd452d2dac349a0c.jpg\",\"fileName\":\"QQ图片20210630102637.jpg\"}}', 0, '', '2023-02-20 11:32:50'); +INSERT INTO `sys_oper_log` VALUES (1627511670681145345, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627511668344918018\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/c4a4c3092b1e4c5cba341caafc0890a5.jpg\",\"fileName\":\"bg.jpg\"}}', 0, '', '2023-02-20 11:33:15'); +INSERT INTO `sys_oper_log` VALUES (1627511792068497410, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627511791024115714\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/39f290cc5fc244eaaf79f0f48d14b316.jpg\",\"fileName\":\"QQ图片20210630102619.jpg\"}}', 0, '', '2023-02-20 11:33:44'); +INSERT INTO `sys_oper_log` VALUES (1627529841039413250, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627529839412023298\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/40bdcd90d42b4d34aa89ecd64016229b.jpg\",\"fileName\":\"QQ图片20210630134357.jpg\"}}', 0, '', '2023-02-20 12:45:27'); +INSERT INTO `sys_oper_log` VALUES (1627530044001783809, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627530023676186625\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/93d6d39a2103496f969ca8c3d83a0aaa.jpg\",\"fileName\":\"QQ图片20210630102642.jpg\"}}', 0, '', '2023-02-20 12:46:15'); +INSERT INTO `sys_oper_log` VALUES (1627530373174956033, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627530371480457218\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/3d966f171aec430d86a3bbea9c04e1e0.jpg\",\"fileName\":\"QQ图片20210630123442.jpg\"}}', 0, '', '2023-02-20 12:47:34'); +INSERT INTO `sys_oper_log` VALUES (1627531673199480833, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627531672146710530\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/c1125cdf905c437cba44833617ab531b.jpg\",\"fileName\":\"QQ图片20210630102637.jpg\"}}', 0, '', '2023-02-20 12:52:44'); +INSERT INTO `sys_oper_log` VALUES (1627532282497634306, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627532280811524097\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/1675166ba2be427385fb412fb10e5f94.jpg\",\"fileName\":\"QQ图片20210630104247.jpg\"}}', 0, '', '2023-02-20 12:55:09'); +INSERT INTO `sys_oper_log` VALUES (1627534210719846401, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627534209742573569\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/4163a7b8abfa4b99a957c6fd40349736.jpg\",\"fileName\":\"QQ图片20210630102642.jpg\"}}', 0, '', '2023-02-20 13:02:49'); +INSERT INTO `sys_oper_log` VALUES (1627535584610258946, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627535582852845569\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/36d78492c4b14db5ad97bf66d1403a5a.jpg\",\"fileName\":\"bg.jpg\"}}', 0, '', '2023-02-20 13:08:16'); +INSERT INTO `sys_oper_log` VALUES (1627536508116307969, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627536506291785729\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/14f71b942c7b4afcb5c58ceb454800ea.jpg\",\"fileName\":\"QQ图片20210630102619.jpg\"}}', 0, '', '2023-02-20 13:11:56'); +INSERT INTO `sys_oper_log` VALUES (1627536710353063938, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627536708662759425\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/0d08292815454dcd9a3f2ff2b9baad8a.jpg\",\"fileName\":\"QQ图片20210630104227.jpg\"}}', 0, '', '2023-02-20 13:12:45'); +INSERT INTO `sys_oper_log` VALUES (1627537622157004802, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537597880373250\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/7e23633378da4f74957de13fa4dfc267.jpg\",\"fileName\":\"QQ图片20210630104227.jpg\"}}', 0, '', '2023-02-20 13:16:22'); +INSERT INTO `sys_oper_log` VALUES (1627537695494410242, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537693686665218\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/5dead792e5c74d47bf779e2e3af6bc0c.jpg\",\"fileName\":\"QQ图片20210630104247.jpg\"}}', 0, '', '2023-02-20 13:16:39'); +INSERT INTO `sys_oper_log` VALUES (1627537801836793857, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537800050020353\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/db579a99836047d6b12e03150dd93506.jpg\",\"fileName\":\"QQ图片20210630104301.jpg\"}}', 0, '', '2023-02-20 13:17:05'); +INSERT INTO `sys_oper_log` VALUES (1627537807918534657, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537806861570050\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/9755790db5df49549c65e7792d09a718.jpg\",\"fileName\":\"QQ图片20210630104227.jpg\"}}', 0, '', '2023-02-20 13:17:06'); +INSERT INTO `sys_oper_log` VALUES (1627537811844403202, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537810158292994\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/61b276351e2148c699808b27cd191f7e.jpg\",\"fileName\":\"QQ图片20210630134408.jpg\"}}', 0, '', '2023-02-20 13:17:07'); +INSERT INTO `sys_oper_log` VALUES (1627537823252910082, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537821663268865\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/101d48888ddd47c99c36c3f83a3844a7.jpg\",\"fileName\":\"QQ图片20210630134405.jpg\"}}', 0, '', '2023-02-20 13:17:10'); +INSERT INTO `sys_oper_log` VALUES (1627537930186690561, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627537928395722754\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/40f81a32f577464fac47933fdd14d9fa.jpg\",\"fileName\":\"789672.jpg\"}}', 0, '', '2023-02-20 13:17:35'); +INSERT INTO `sys_oper_log` VALUES (1627539510432665601, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539508666863618\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/9d75283ccbda4d38b72293c3ece90af9.jpg\",\"fileName\":\"290072.jpg\"}}', 0, '', '2023-02-20 13:23:52'); +INSERT INTO `sys_oper_log` VALUES (1627539514878627841, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539513163157505\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/3fcd6fb825484eb1accec5fd1b805667.jpg\",\"fileName\":\"QQ图片20210630102645.jpg\"}}', 0, '', '2023-02-20 13:23:53'); +INSERT INTO `sys_oper_log` VALUES (1627539523401453569, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539521610485762\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/7925a23fc65e4b3b82ae85d79ecc65c8.jpg\",\"fileName\":\"QQ图片20210630102619.jpg\"}}', 0, '', '2023-02-20 13:23:55'); +INSERT INTO `sys_oper_log` VALUES (1627539530670182401, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539529046986753\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/70e2e6777de04562979d3a42af939914.jpg\",\"fileName\":\"798004.jpg\"}}', 0, '', '2023-02-20 13:23:57'); +INSERT INTO `sys_oper_log` VALUES (1627539544192618497, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539542598782978\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/5014c280255c42c6b0ceee9bab64b5fc.jpeg\",\"fileName\":\"digitalart,城市,未来,猫,fantasyart,科幻_千叶网.jpeg\"}}', 0, '', '2023-02-20 13:24:00'); +INSERT INTO `sys_oper_log` VALUES (1627539549389361154, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539548277870594\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/5d0070200e2a49e4bceca0e255dd2a2d.jpg\",\"fileName\":\"QQ图片20210630102642.jpg\"}}', 0, '', '2023-02-20 13:24:01'); +INSERT INTO `sys_oper_log` VALUES (1627539728595193857, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627539726816808962\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/2e089b929d0d4c05b317be1b8509dc23.jpg\",\"fileName\":\"宇宙.jpg\"}}', 0, '', '2023-02-20 13:24:44'); +INSERT INTO `sys_oper_log` VALUES (1627542648199876609, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627542645771374593\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/426c4f1e9b2644628c74a31994ce9481.jpg\",\"fileName\":\"QQ图片20210630104247.jpg\"}}', 0, '', '2023-02-20 13:36:20'); +INSERT INTO `sys_oper_log` VALUES (1627544877321457666, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627544875626958850\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/e1cc961801a949a291370a99e400349b.jpeg\",\"fileName\":\"digitalart,城市,未来,猫,fantasyart,科幻_千叶网.jpeg\"}}', 0, '', '2023-02-20 13:45:12'); +INSERT INTO `sys_oper_log` VALUES (1627556658781655041, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627556657644998657\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/eaadf85450f1410dab0478eb37c19cf7.jpeg\",\"fileName\":\"thelastofus,apocalyptic_千叶网.jpeg\"}}', 0, '', '2023-02-20 14:32:01'); +INSERT INTO `sys_oper_log` VALUES (1627556771088338945, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627556770035568641\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/65859e6d993e44b298f294a728a5b731.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-20 14:32:27'); +INSERT INTO `sys_oper_log` VALUES (1627556785961340929, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":154,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1627556770035568641\",\"articleTitle\":\"测试\",\"articleContent\":\"![DESC](http://127.0.0.1:9000/blog/2023/02/20/eaadf85450f1410dab0478eb37c19cf7.jpeg)\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 14:32:31'); +INSERT INTO `sys_oper_log` VALUES (1627557207899934721, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627557206851358722\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/d90a424b6e734cdea66a48af80338338.jpg\",\"fileName\":\"Life,is,Strange,23440x1440带鱼屏壁纸_千叶网.jpg\"}}', 0, '', '2023-02-20 14:34:12'); +INSERT INTO `sys_oper_log` VALUES (1627561975720480769, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627561973971456001\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/92b4709cdc5b497e8b08f3b23ac4be37.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-20 14:53:08'); +INSERT INTO `sys_oper_log` VALUES (1627613439021060097, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 18:17:37\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 18:17:37\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1627613437242675202\",\"menuName\":\"相册管理\",\"orderNum\":4,\"path\":\"albums\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"phone\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 18:17:38'); +INSERT INTO `sys_oper_log` VALUES (1627613774808649730, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 18:18:57\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 18:18:57\",\"parentName\":null,\"parentId\":\"1627613437242675202\",\"children\":[],\"menuId\":\"1627613773059624962\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/Album.vue\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"example\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 18:18:58'); +INSERT INTO `sys_oper_log` VALUES (1627635890568335361, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1627613773059624962', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 19:46:51'); +INSERT INTO `sys_oper_log` VALUES (1627635902572433409, '菜单管理', 3, 'com.zhi.web.controller.system.SysMenuController.remove()', 'DELETE', 1, 'admin', '', '/system/menu/1627613437242675202', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 19:46:54'); +INSERT INTO `sys_oper_log` VALUES (1627638279127994370, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '4.2.2.2', ' ', '\"blog_photo_album\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 19:56:20'); +INSERT INTO `sys_oper_log` VALUES (1627638807874539522, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:58:26\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":null},\"tableId\":\"1627638276586246146\",\"tableName\":\"blog_photo_album\",\"tableComment\":\"相册管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Album\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"album\",\"businessName\":\"Album\",\"functionName\":\"相册管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:58:26\",\"columnId\":\"1627638276653355010\",\"tableId\":\"1627638276586246146\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"superColumn\":false,\"pk\":true,\"edit\":true,\"insert\":false,\"usableColumn\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:58:26\",\"columnId\":\"1627638276653355011\",\"tableId\":\"1627638276586246146\",\"columnName\":\"album_name\",\"columnComment\":\"相册名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"albumName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"superColumn\":false,\"pk\":false,\"edit\":true,\"insert\":true,\"usableColumn\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"AlbumName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:58:26\",\"columnId\":\"1627638276653355012\",\"tableId\":\"1627638276586246146\",\"columnName\":\"album_desc\",\"columnComment\":\"相册描述\",\"columnType\":\"varchar(50)\",\"javaTyp', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 19:58:27'); +INSERT INTO `sys_oper_log` VALUES (1627639008316133378, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:59:14\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":null},\"tableId\":\"1627638276586246146\",\"tableName\":\"blog_photo_album\",\"tableComment\":\"相册管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Album\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"album\",\"businessName\":\"album\",\"functionName\":\"相册管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:59:14\",\"columnId\":\"1627638276653355010\",\"tableId\":\"1627638276586246146\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"superColumn\":false,\"pk\":true,\"edit\":true,\"insert\":false,\"usableColumn\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:59:14\",\"columnId\":\"1627638276653355011\",\"tableId\":\"1627638276586246146\",\"columnName\":\"album_name\",\"columnComment\":\"相册名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"albumName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"superColumn\":false,\"pk\":false,\"edit\":true,\"insert\":true,\"usableColumn\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"AlbumName\"},{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 19:59:14\",\"columnId\":\"1627638276653355012\",\"tableId\":\"1627638276586246146\",\"columnName\":\"album_desc\",\"columnComment\":\"相册描述\",\"columnType\":\"varchar(50)\",\"javaTyp', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 19:59:14'); +INSERT INTO `sys_oper_log` VALUES (1627639040209620994, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '4.2.2.2', ' ', '{\"tables\":\"blog_photo_album\"}', '', 0, '', '2023-02-20 19:59:22'); +INSERT INTO `sys_oper_log` VALUES (1627641229317521410, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '127.0.0.1', '内网IP', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:08:03\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1627639037193916416\",\"menuName\":\"相册管理\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:list\",\"icon\":\"#\",\"remark\":\"相册管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:08:04'); +INSERT INTO `sys_oper_log` VALUES (1627641510222643201, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:09:10\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1627639037193916416\",\"menuName\":\"相册管理\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:list\",\"icon\":\"#\",\"remark\":\"相册管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:09:11'); +INSERT INTO `sys_oper_log` VALUES (1627641734093619201, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:10:03\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:10:03\",\"parentName\":null,\"parentId\":\"1627639037193916416\",\"children\":[],\"menuId\":\"1627641732344594434\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"build\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:10:04'); +INSERT INTO `sys_oper_log` VALUES (1627641927472005121, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:10:49\",\"parentName\":null,\"parentId\":\"1627641732344594434\",\"children\":[],\"menuId\":\"1627639037193916418\",\"menuName\":\"相册管理新增\",\"orderNum\":2,\"path\":\"#\",\"component\":\"\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"F\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:add\",\"icon\":\"#\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:10:50'); +INSERT INTO `sys_oper_log` VALUES (1627641959738785793, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:10:57\",\"parentName\":null,\"parentId\":\"1627641732344594434\",\"children\":[],\"menuId\":\"1627639037193916419\",\"menuName\":\"相册管理修改\",\"orderNum\":3,\"path\":\"#\",\"component\":\"\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"F\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:edit\",\"icon\":\"#\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:10:58'); +INSERT INTO `sys_oper_log` VALUES (1627641998884225026, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:11:06\",\"parentName\":null,\"parentId\":\"1627641732344594434\",\"children\":[],\"menuId\":\"1627639037193916420\",\"menuName\":\"相册管理删除\",\"orderNum\":4,\"path\":\"#\",\"component\":\"\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"F\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:remove\",\"icon\":\"#\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:11:07'); +INSERT INTO `sys_oper_log` VALUES (1627642025320923137, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:11:13\",\"parentName\":null,\"parentId\":\"1627641732344594434\",\"children\":[],\"menuId\":\"1627639037193916417\",\"menuName\":\"相册管理查询\",\"orderNum\":1,\"path\":\"#\",\"component\":\"\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"F\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:query\",\"icon\":\"#\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:11:14'); +INSERT INTO `sys_oper_log` VALUES (1627642049081655297, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:11:18\",\"parentName\":null,\"parentId\":\"1627641732344594434\",\"children\":[],\"menuId\":\"1627639037193916421\",\"menuName\":\"相册管理导出\",\"orderNum\":5,\"path\":\"#\",\"component\":\"\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"F\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:export\",\"icon\":\"#\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:11:19'); +INSERT INTO `sys_oper_log` VALUES (1627642194154242049, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:10:04\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:11:49\",\"parentName\":null,\"parentId\":\"1627639037193916416\",\"children\":[],\"menuId\":\"1627641732344594434\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"build\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:11:54'); +INSERT INTO `sys_oper_log` VALUES (1627642569422815234, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:10:04\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:13:22\",\"parentName\":null,\"parentId\":\"1627639037193916416\",\"children\":[],\"menuId\":\"1627641732344594434\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"build\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:13:23'); +INSERT INTO `sys_oper_log` VALUES (1627642634212229121, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:02:59\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:13:38\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1627639037193916416\",\"menuName\":\"相册管理\",\"orderNum\":2,\"path\":\"album\",\"component\":\"album/album/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:list\",\"icon\":\"chart\",\"remark\":\"相册管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:13:39'); +INSERT INTO `sys_oper_log` VALUES (1627642999389306882, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:15:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:15:05\",\"parentName\":null,\"parentId\":0,\"children\":[],\"menuId\":\"1627642998340730881\",\"menuName\":\"相册管理\",\"orderNum\":2,\"path\":\"album\",\"component\":null,\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"M\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"build\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:15:06'); +INSERT INTO `sys_oper_log` VALUES (1627643093526265857, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:15:27\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1627642998340730881\"},\"tableId\":\"1627638276586246146\",\"tableName\":\"blog_photo_album\",\"tableComment\":\"相册管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Album\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"album\",\"businessName\":\"album\",\"functionName\":\"相册管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:15:27\",\"columnId\":\"1627638276653355010\",\"tableId\":\"1627638276586246146\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"superColumn\":false,\"edit\":true,\"query\":false,\"capJavaField\":\"Id\",\"increment\":true},{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:15:27\",\"columnId\":\"1627638276653355011\",\"tableId\":\"1627638276586246146\",\"columnName\":\"album_name\",\"columnComment\":\"相册名\",\"columnType\":\"varchar(20)\",\"javaType\":\"String\",\"javaField\":\"albumName\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"LIKE\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"superColumn\":false,\"edit\":true,\"query\":true,\"capJavaField\":\"AlbumName\",\"increment\":false},{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 19:56:20\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:15:27\",\"columnId\":\"1627638276653355012\",\"tableId\":\"1627638276586246146\",\"columnName\":\"album_desc\",\"columnComment\":\"相册描述\",\"columnType\":\"varc', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:15:28'); +INSERT INTO `sys_oper_log` VALUES (1627643114850107394, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '4.2.2.2', ' ', '{\"tables\":\"blog_photo_album\"}', '', 0, '', '2023-02-20 20:15:33'); +INSERT INTO `sys_oper_log` VALUES (1627643465665888258, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:16:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 20:16:56\",\"parentName\":null,\"parentId\":\"1627642998340730881\",\"children\":[],\"menuId\":\"1627643112476131328\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album/index\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:list\",\"icon\":\"#\",\"remark\":\"相册管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:16:57'); +INSERT INTO `sys_oper_log` VALUES (1627645267471777793, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627645265534009346\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/62389e369ae64d61a26c756aa9e42dd8.jpeg\",\"fileName\":\"Spider,Man,MaviC漫画,漫画,蜘蛛,超级英雄,标志,黑暗_千叶网.jpeg\"}}', 0, '', '2023-02-20 20:24:07'); +INSERT INTO `sys_oper_log` VALUES (1627645455175270401, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627645452625133569\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/f5c1f42c1e084aa0aee90cb929fd441d.jpg\",\"fileName\":\"Riffelsee里弗尔湖3440x1440风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-20 20:24:51'); +INSERT INTO `sys_oper_log` VALUES (1627645791646535681, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":null,\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"1627645452625133569\",\"isDelete\":null,\"status\":0}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1\n; Data truncation: Out of range value for column \'id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'id\' at row 1', '2023-02-20 20:26:12'); +INSERT INTO `sys_oper_log` VALUES (1627646020739420161, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627646019632123906\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"1627645452625133569\",\"isDelete\":null,\"status\":0}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 20:27:06'); +INSERT INTO `sys_oper_log` VALUES (1627657037682843649, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:16:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-20 21:10:47\",\"parentName\":null,\"parentId\":\"1627642998340730881\",\"children\":[],\"menuId\":\"1627643112476131328\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album/Album\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:list\",\"icon\":\"#\",\"remark\":\"相册管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 21:10:53'); +INSERT INTO `sys_oper_log` VALUES (1627657202904866817, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627646019632123906\",\"albumName\":\"测试2\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/20/f5c1f42c1e084aa0aee90cb929fd441d.jpg\",\"isDelete\":0,\"status\":0}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627646019632123906\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627646019632123906\' for key \'PRIMARY\'\n; Duplicate entry \'1627646019632123906\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627646019632123906\' for key \'PRIMARY\'', '2023-02-20 21:11:32'); +INSERT INTO `sys_oper_log` VALUES (1627658267767349250, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627646019632123906', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 21:15:46'); +INSERT INTO `sys_oper_log` VALUES (1627665762942459906, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627665761763860482\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/731df6e97c8f461a9b4b60b301d833a3.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-20 21:45:33'); +INSERT INTO `sys_oper_log` VALUES (1627665816679882753, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627665814859554817\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/20/731df6e97c8f461a9b4b60b301d833a3.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 21:45:46'); +INSERT INTO `sys_oper_log` VALUES (1627666192242057218, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627666190476255233\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/83c7f5de63634221951855a1a0649058.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-20 21:47:15'); +INSERT INTO `sys_oper_log` VALUES (1627666216036343809, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627666215004545026\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"1627666190476255233\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 21:47:21'); +INSERT INTO `sys_oper_log` VALUES (1627666936890519553, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627666215004545026', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 21:50:13'); +INSERT INTO `sys_oper_log` VALUES (1627666978418323457, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627666975754940417\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/8a5338914aa145da9cbc54dfa7736cee.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-20 21:50:23'); +INSERT INTO `sys_oper_log` VALUES (1627666984240017410, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627666982407106562\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/20/8a5338914aa145da9cbc54dfa7736cee.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-20 21:50:24'); +INSERT INTO `sys_oper_log` VALUES (1627667033590198274, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627667031962808322\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/af418a8aca0f4095a8e30ca3136db686.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-20 21:50:36'); +INSERT INTO `sys_oper_log` VALUES (1627667038480756738, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627666982407106562\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/20/af418a8aca0f4095a8e30ca3136db686.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\n; Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'', '2023-02-20 21:50:37'); +INSERT INTO `sys_oper_log` VALUES (1627673598292520962, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627673595939516418\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/20/bc7e25049822464abee816506fb51bc0.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-20 22:16:41'); +INSERT INTO `sys_oper_log` VALUES (1627673609935908865, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627666982407106562\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/20/bc7e25049822464abee816506fb51bc0.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\n; Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'', '2023-02-20 22:16:44'); +INSERT INTO `sys_oper_log` VALUES (1627852988309696513, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627852985965080577\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/a91dda88952d4e3fa8a821e91ad934e8.jpg\",\"fileName\":\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:09:31'); +INSERT INTO `sys_oper_log` VALUES (1627852991732248578, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1627852985965080577\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:09:32'); +INSERT INTO `sys_oper_log` VALUES (1627854299289743361, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627854297444249601\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/8f2a717137b646acbff87adadd57dbb2.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-21 10:14:44'); +INSERT INTO `sys_oper_log` VALUES (1627854305107243009, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627666982407106562\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/8f2a717137b646acbff87adadd57dbb2.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\n; Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'', '2023-02-21 10:14:45'); +INSERT INTO `sys_oper_log` VALUES (1627855930416820226, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627855928726515714\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/9a820a2dcdb542b49351b5bf221d2e66.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:21:13'); +INSERT INTO `sys_oper_log` VALUES (1627855940969689090, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627666982407106562\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/20/8a5338914aa145da9cbc54dfa7736cee.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'\n; Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627666982407106562\' for key \'PRIMARY\'', '2023-02-21 10:21:15'); +INSERT INTO `sys_oper_log` VALUES (1627856440045613058, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627666982407106562', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:23:14'); +INSERT INTO `sys_oper_log` VALUES (1627856490381455361, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627856486984069121\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/2c7f4a4f245a429db3dc048c4f0b96f6.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-21 10:23:26'); +INSERT INTO `sys_oper_log` VALUES (1627857022709936130, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627857021028020225\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/fe9add89604f4bf19f5831f9a6d00090.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-21 10:25:33'); +INSERT INTO `sys_oper_log` VALUES (1627857382304395265, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627857380664422402\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/9a2403427c2040f98927106ea09ad42f.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-21 10:26:59'); +INSERT INTO `sys_oper_log` VALUES (1627857387211730945, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627857385458511873\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"1627857380664422402\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:27:00'); +INSERT INTO `sys_oper_log` VALUES (1627857824014938113, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1627857380664422402', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:28:44'); +INSERT INTO `sys_oper_log` VALUES (1627857833913495554, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627857832864919553\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/646d4ee4f3ac4476b947fbdb74cd00f5.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:28:46'); +INSERT INTO `sys_oper_log` VALUES (1627857838007136257, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627857385458511873\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"1627857832864919553\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627857385458511873\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627857385458511873\' for key \'PRIMARY\'\n; Duplicate entry \'1627857385458511873\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627857385458511873\' for key \'PRIMARY\'', '2023-02-21 10:28:47'); +INSERT INTO `sys_oper_log` VALUES (1627858872054067201, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627857385458511873', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:32:54'); +INSERT INTO `sys_oper_log` VALUES (1627860020618080257, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627860018860666882\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/b1c77c7cbfc14d8ebf3cd415ce74baa6.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:37:28'); +INSERT INTO `sys_oper_log` VALUES (1627860024481034242, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860023315017730\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/b1c77c7cbfc14d8ebf3cd415ce74baa6.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:37:29'); +INSERT INTO `sys_oper_log` VALUES (1627860305797226498, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627860023315017730', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:38:36'); +INSERT INTO `sys_oper_log` VALUES (1627860337048985602, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627860331508310018\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/d4c7295727dc40749df1fdf921e593fc.png\",\"fileName\":\"超宽,空间,蓝色_千叶网.png\"}}', 0, '', '2023-02-21 10:38:43'); +INSERT INTO `sys_oper_log` VALUES (1627860338680569857, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/d4c7295727dc40749df1fdf921e593fc.png\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:38:44'); +INSERT INTO `sys_oper_log` VALUES (1627860390060793858, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627860387489685505\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/19663e839bb44b6f9b6e302150e718d6.jpg\",\"fileName\":\"超人总动员23440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:38:56'); +INSERT INTO `sys_oper_log` VALUES (1627860393965690881, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/19663e839bb44b6f9b6e302150e718d6.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\n; Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'', '2023-02-21 10:38:57'); +INSERT INTO `sys_oper_log` VALUES (1627861561097887746, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627861559386611714\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/5f07677143514124adb4fa3f72a07874.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:43:35'); +INSERT INTO `sys_oper_log` VALUES (1627861565896171522, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/5f07677143514124adb4fa3f72a07874.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\n; Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'', '2023-02-21 10:43:36'); +INSERT INTO `sys_oper_log` VALUES (1627862001101348865, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"1233\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/d4c7295727dc40749df1fdf921e593fc.png\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\n; Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'', '2023-02-21 10:45:20'); +INSERT INTO `sys_oper_log` VALUES (1627862190193156097, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627862189152968706\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/5e6599b7be004731a9f56200ae01b715.jpg\",\"fileName\":\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:46:05'); +INSERT INTO `sys_oper_log` VALUES (1627862196841127938, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/5e6599b7be004731a9f56200ae01b715.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\n; Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'', '2023-02-21 10:46:07'); +INSERT INTO `sys_oper_log` VALUES (1627863022376624129, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627863020413689857\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/da68286bc2654d559d047d63df24343c.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:49:23'); +INSERT INTO `sys_oper_log` VALUES (1627863027732750337, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/da68286bc2654d559d047d63df24343c.jpg\",\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/AlbumMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.AlbumMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo_album ( id, album_name, album_desc, album_cover, is_delete, status, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'\n; Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1627860336587612162\' for key \'PRIMARY\'', '2023-02-21 10:49:25'); +INSERT INTO `sys_oper_log` VALUES (1627863433049317377, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627863430687924226\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/4330028b55a74589a9f01d1f9ba43bcf.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-21 10:51:01'); +INSERT INTO `sys_oper_log` VALUES (1627863436274737153, '相册管理', 2, 'com.zhi.blog.controller.AlbumController.edit()', 'PUT', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/4330028b55a74589a9f01d1f9ba43bcf.jpg\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:51:02'); +INSERT INTO `sys_oper_log` VALUES (1627863463810342913, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627863462698852353\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/fca5c4d3b0e8497b84206a03a3bb2dad.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 10:51:09'); +INSERT INTO `sys_oper_log` VALUES (1627863468428271617, '相册管理', 2, 'com.zhi.blog.controller.AlbumController.edit()', 'PUT', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/fca5c4d3b0e8497b84206a03a3bb2dad.jpg\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:51:10'); +INSERT INTO `sys_oper_log` VALUES (1627863526917840897, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627863525214953473\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/2260141bf2934ef6b68ff50adcde79f0.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-21 10:51:24'); +INSERT INTO `sys_oper_log` VALUES (1627863532320104450, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627863530621411330\",\"albumName\":\"555\",\"albumDesc\":\"555\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/2260141bf2934ef6b68ff50adcde79f0.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:51:25'); +INSERT INTO `sys_oper_log` VALUES (1627863720036179970, '相册管理', 2, 'com.zhi.blog.controller.AlbumController.edit()', 'PUT', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627863530621411330\",\"albumName\":\"555\",\"albumDesc\":\"555\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/2260141bf2934ef6b68ff50adcde79f0.jpg\",\"isDelete\":0,\"status\":2}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:52:10'); +INSERT INTO `sys_oper_log` VALUES (1627863815666311170, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627863530621411330', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 10:52:33'); +INSERT INTO `sys_oper_log` VALUES (1627992307968012289, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1627992305770196994\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/17e1d88be409433ca4f672b2f0988700.jpg\",\"fileName\":\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 19:23:08'); +INSERT INTO `sys_oper_log` VALUES (1627992314733424641, '相册管理', 2, 'com.zhi.blog.controller.AlbumController.edit()', 'PUT', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"123\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/17e1d88be409433ca4f672b2f0988700.jpg\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:23:09'); +INSERT INTO `sys_oper_log` VALUES (1627992457113268225, '相册管理', 2, 'com.zhi.blog.controller.AlbumController.edit()', 'PUT', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1627860336587612162\",\"albumName\":\"测试\",\"albumDesc\":\"123\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/21/17e1d88be409433ca4f672b2f0988700.jpg\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:23:43'); +INSERT INTO `sys_oper_log` VALUES (1627992803743133697, '代码生成', 6, 'com.zhi.generator.controller.GenController.importTableSave()', 'POST', 1, 'admin', '', '/tool/gen/importTable', '4.2.2.2', ' ', '\"blog_photo\"', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:25:06'); +INSERT INTO `sys_oper_log` VALUES (1627996832997076993, '菜单管理', 1, 'com.zhi.web.controller.system.SysMenuController.add()', 'POST', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-21 19:41:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:41:05\",\"parentName\":null,\"parentId\":\"1627642998340730881\",\"children\":[],\"menuId\":\"1627996831193526274\",\"menuName\":\"照片管理\",\"orderNum\":2,\"path\":\"photo\",\"component\":null,\"queryParam\":\"album/album/Photo\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"eye-open\",\"remark\":null}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:41:06'); +INSERT INTO `sys_oper_log` VALUES (1627996993454370817, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-21 19:41:06\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:41:44\",\"parentName\":null,\"parentId\":\"1627642998340730881\",\"children\":[],\"menuId\":\"1627996831193526274\",\"menuName\":\"照片管理\",\"orderNum\":2,\"path\":\"photo\",\"component\":\"album/album/Photo\",\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"icon\":\"eye-open\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:41:45'); +INSERT INTO `sys_oper_log` VALUES (1627997087301922817, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-20 20:16:08\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:42:06\",\"parentName\":null,\"parentId\":\"1627642998340730881\",\"children\":[],\"menuId\":\"1627643112476131328\",\"menuName\":\"相册列表\",\"orderNum\":1,\"path\":\"album\",\"component\":\"album/album/Album\",\"queryParam\":null,\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"0\",\"status\":\"0\",\"perms\":\"album:album:list\",\"icon\":\"list\",\"remark\":\"相册管理菜单\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:42:07'); +INSERT INTO `sys_oper_log` VALUES (1627998192618467329, '代码生成', 2, 'com.zhi.generator.controller.GenController.editSave()', 'PUT', 1, 'admin', '', '/tool/gen', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:46:29\",\"params\":{\"treeCode\":null,\"treeName\":null,\"treeParentCode\":null,\"parentMenuId\":\"1627642998340730881\"},\"tableId\":\"1627992801939582977\",\"tableName\":\"blog_photo\",\"tableComment\":\"照片管理\",\"subTableName\":null,\"subTableFkName\":null,\"className\":\"Photo\",\"tplCategory\":\"crud\",\"packageName\":\"com.zhi.blog\",\"moduleName\":\"photo\",\"businessName\":\"photo\",\"functionName\":\"照片管理\",\"functionAuthor\":\"ftz\",\"genType\":\"0\",\"genPath\":\"/\",\"pkColumn\":null,\"subTable\":null,\"columns\":[{\"createBy\":\"admin\",\"createTime\":\"2023-02-21 19:25:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:46:29\",\"columnId\":\"1627992802002497537\",\"tableId\":\"1627992801939582977\",\"columnName\":\"id\",\"columnComment\":\"主键\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"id\",\"isPk\":\"1\",\"isIncrement\":\"1\",\"isRequired\":\"1\",\"isInsert\":null,\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":null,\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":1,\"required\":true,\"list\":true,\"pk\":true,\"usableColumn\":false,\"insert\":false,\"edit\":true,\"superColumn\":false,\"increment\":true,\"query\":false,\"capJavaField\":\"Id\"},{\"createBy\":\"admin\",\"createTime\":\"2023-02-21 19:25:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:46:29\",\"columnId\":\"1627992802002497538\",\"tableId\":\"1627992801939582977\",\"columnName\":\"album_id\",\"columnComment\":\"相册id\",\"columnType\":\"int(11)\",\"javaType\":\"Long\",\"javaField\":\"albumId\",\"isPk\":\"0\",\"isIncrement\":\"0\",\"isRequired\":\"1\",\"isInsert\":\"1\",\"isEdit\":\"1\",\"isList\":\"1\",\"isQuery\":\"1\",\"queryType\":\"EQ\",\"htmlType\":\"input\",\"dictType\":\"\",\"sort\":2,\"required\":true,\"list\":true,\"pk\":false,\"usableColumn\":false,\"insert\":true,\"edit\":true,\"superColumn\":false,\"increment\":false,\"query\":true,\"capJavaField\":\"AlbumId\"},{\"createBy\":\"admin\",\"createTime\":\"2023-02-21 19:25:05\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-21 19:46:29\",\"columnId\":\"1627992802002497539\",\"tableId\":\"1627992801939582977\",\"columnName\":\"photo_name\",\"columnComment\":\"照片名\",\"columnType\":\"varchar(20)\",\"javaType\":', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-21 19:46:31'); +INSERT INTO `sys_oper_log` VALUES (1627998296507183105, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '4.2.2.2', ' ', '{\"tables\":\"blog_photo\"}', '', 0, '', '2023-02-21 19:46:55'); +INSERT INTO `sys_oper_log` VALUES (1627998355462320130, '代码生成', 8, 'com.zhi.generator.controller.GenController.batchGenCode()', 'GET', 1, 'admin', '', '/tool/gen/batchGenCode', '4.2.2.2', ' ', '{\"tables\":\"blog_photo\"}', '', 0, '', '2023-02-21 19:47:09'); +INSERT INTO `sys_oper_log` VALUES (1628011020461129730, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628011018313646082\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/7d6d21febed94f7389f98fe5d485166a.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 20:37:29'); +INSERT INTO `sys_oper_log` VALUES (1628011334799048705, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628011333062606850\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/b4700c8797e0487abada6fe0fa0d81ab.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 20:38:44'); +INSERT INTO `sys_oper_log` VALUES (1628011436074713089, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628011433562324994\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/ae76c713607146a5bf03cc789c11a8f6.jpeg\",\"fileName\":\"scarlettjohansson,抽象,doubleexposure,undertheskin_千叶网.jpeg\"}}', 0, '', '2023-02-21 20:39:08'); +INSERT INTO `sys_oper_log` VALUES (1628012808505507841, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628012795993899009\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/7269a13857364af5ac18d6959c058bd1.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-21 20:44:35'); +INSERT INTO `sys_oper_log` VALUES (1628015590931283969, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628015589643632641\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/a658e31cf6764a0d80fc0e071077afec.png\",\"fileName\":\"超宽,空间,蓝色_千叶网.png\"}}', 0, '', '2023-02-21 20:55:39'); +INSERT INTO `sys_oper_log` VALUES (1628027196885000194, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628027195207278594\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/33a8fea53e0c42da8d6ed01a39e9f859.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-21 21:41:46'); +INSERT INTO `sys_oper_log` VALUES (1628027203851739137, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":null}', '', 1, '', '2023-02-21 21:41:47'); +INSERT INTO `sys_oper_log` VALUES (1628027442369224705, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":null}', '', 1, '', '2023-02-21 21:42:44'); +INSERT INTO `sys_oper_log` VALUES (1628027633931476993, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628027632060817410\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/61d2d3ae38d1481c8ad91d33bf6a2b72.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 21:43:30'); +INSERT INTO `sys_oper_log` VALUES (1628027638369050626, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":null}', '', 1, '', '2023-02-21 21:43:31'); +INSERT INTO `sys_oper_log` VALUES (1628027970708922370, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628027968905371649\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/da8f803220494db1a373a3c71c696a5f.png\",\"fileName\":\"超宽,空间,蓝色_千叶网.png\"}}', 0, '', '2023-02-21 21:44:50'); +INSERT INTO `sys_oper_log` VALUES (1628027975020666882, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/21/da8f803220494db1a373a3c71c696a5f.png\"]}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1\n; Data truncation: Out of range value for column \'album_id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1', '2023-02-21 21:44:51'); +INSERT INTO `sys_oper_log` VALUES (1628028429238624258, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/21/da8f803220494db1a373a3c71c696a5f.png\"]}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1\n; Data truncation: Out of range value for column \'album_id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1', '2023-02-21 21:46:39'); +INSERT INTO `sys_oper_log` VALUES (1628028982945472513, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628028981204836354\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/c3666fdb056d48138fa42188409cd573.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-21 21:48:52'); +INSERT INTO `sys_oper_log` VALUES (1628028987777310722, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/21/c3666fdb056d48138fa42188409cd573.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1\n; Data truncation: Out of range value for column \'album_id\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Out of range value for column \'album_id\' at row 1', '2023-02-21 21:48:53'); +INSERT INTO `sys_oper_log` VALUES (1628029253759098881, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628029252077182977\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/53c5a85233d54585970a9de6cb5367d8.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-21 21:49:56'); +INSERT INTO `sys_oper_log` VALUES (1628029311179120641, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/21/53c5a85233d54585970a9de6cb5367d8.jpeg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\n; Field \'photo_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value', '2023-02-21 21:50:10'); +INSERT INTO `sys_oper_log` VALUES (1628029349653471234, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/21/53c5a85233d54585970a9de6cb5367d8.jpeg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\n; Field \'photo_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value', '2023-02-21 21:50:19'); +INSERT INTO `sys_oper_log` VALUES (1628030551346733058, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628030545277575170\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/21/6ed5fcb5331b45eea2bfc372914fbf4b.jpeg\",\"fileName\":\"thelastofus,apocalyptic_千叶网.jpeg\"}}', 0, '', '2023-02-21 21:55:05'); +INSERT INTO `sys_oper_log` VALUES (1628215623551115266, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628215622326378497\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/967586ee878d4279803c6464f3d07466.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:10:30'); +INSERT INTO `sys_oper_log` VALUES (1628215636121444353, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628215635026731010\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/2b9cc3d96eb14132b0ac60928f8390ca.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:10:33'); +INSERT INTO `sys_oper_log` VALUES (1628215668509859841, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628215666769223682\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/b7036a7850a848c1b7261de21d540e4a.jpg\",\"fileName\":\"班夫国家公园,湖的平静水域的星空背景3840x2160壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:10:41'); +INSERT INTO `sys_oper_log` VALUES (1628219721763614721, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628219695280779266\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/734c687efc744743b97227fd07ccc725.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:26:47'); +INSERT INTO `sys_oper_log` VALUES (1628219722346622978, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628219695280779267\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/6ca942afd78242d2866b1e01a406773e.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:26:47'); +INSERT INTO `sys_oper_log` VALUES (1628219744660320258, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628219739815899138\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/aef96991e9db4307a55c8f0a63862531.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-22 10:26:53'); +INSERT INTO `sys_oper_log` VALUES (1628219785894522882, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/6ca942afd78242d2866b1e01a406773e.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/22/734c687efc744743b97227fd07ccc725.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/aef96991e9db4307a55c8f0a63862531.jpg\"],\"photoNameList\":[null,null,null]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'album_id\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'album_id\' doesn\'t have a default value\n; Field \'album_id\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'album_id\' doesn\'t have a default value', '2023-02-22 10:27:02'); +INSERT INTO `sys_oper_log` VALUES (1628220088031117314, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/6ca942afd78242d2866b1e01a406773e.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/22/734c687efc744743b97227fd07ccc725.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/aef96991e9db4307a55c8f0a63862531.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/6ca942afd78242d2866b1e01a406773e.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/22/734c687efc744743b97227fd07ccc725.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/aef96991e9db4307a55c8f0a63862531.jpg\"],\"photoNameList\":[null,null,null,null,null,null]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\n; Field \'photo_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value', '2023-02-22 10:28:15'); +INSERT INTO `sys_oper_log` VALUES (1628220410656980994, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628220408979259393\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/2dd52bd1ba6f4686ad2d62ea0cd89de5.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:29:31'); +INSERT INTO `sys_oper_log` VALUES (1628220427937513474, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628220426192683010\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/dab1340ae4aa4e38bf86d976715683b2.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-22 10:29:36'); +INSERT INTO `sys_oper_log` VALUES (1628220442831486978, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/2dd52bd1ba6f4686ad2d62ea0cd89de5.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/dab1340ae4aa4e38bf86d976715683b2.jpg\"],\"photoNameList\":[null,null]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\n; Field \'photo_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value', '2023-02-22 10:29:39'); +INSERT INTO `sys_oper_log` VALUES (1628221179057668098, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628221177908428802\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/ae4e8495d40948a3b106c97279aa4f8d.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:32:35'); +INSERT INTO `sys_oper_log` VALUES (1628221299631325186, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628221293578944514\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/47a5c691debf49b384e5d298b0a3cedb.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:33:03'); +INSERT INTO `sys_oper_log` VALUES (1628221333231894529, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628221330908250113\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/19d0822efcb04dd7847559445223f88d.jpg\",\"fileName\":\"超人总动员23440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:33:11'); +INSERT INTO `sys_oper_log` VALUES (1628221362172592130, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/47a5c691debf49b384e5d298b0a3cedb.jpeg\",null,\"http://127.0.0.1:9000/blog/2023/02/22/19d0822efcb04dd7847559445223f88d.jpg\",null],\"photoNameList\":[null,\"超宽,景观,自然,空间_千叶网.jpeg\",null,\"超人总动员23440x1440壁纸_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\n; Field \'photo_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value', '2023-02-22 10:33:18'); +INSERT INTO `sys_oper_log` VALUES (1628221828084269057, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628221825693515777\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/346727a62a7b4224bc080fda67d6a460.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:35:09'); +INSERT INTO `sys_oper_log` VALUES (1628221838330953729, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628221836590317570\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/6f053e6fe8ef44de828be8541b07f7ba.jpeg\",\"fileName\":\"边境地区_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:35:12'); +INSERT INTO `sys_oper_log` VALUES (1628221845427716097, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/346727a62a7b4224bc080fda67d6a460.jpg\",null,\"http://127.0.0.1:9000/blog/2023/02/22/6f053e6fe8ef44de828be8541b07f7ba.jpeg\",null],\"photoNameList\":[null,\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",null,\"边境地区_千叶网.jpeg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value\n; Field \'photo_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'photo_name\' doesn\'t have a default value', '2023-02-22 10:35:14'); +INSERT INTO `sys_oper_log` VALUES (1628222467568828418, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628222465823997953\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/9b0985edc81b48aead0594c29574f069.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:37:42'); +INSERT INTO `sys_oper_log` VALUES (1628222667737792514, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628222665414148097\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/9d48d6066faa4600b95cde04724a8b1d.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:38:30'); +INSERT INTO `sys_oper_log` VALUES (1628222753343537154, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628222752253018113\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/2abeaa7065764e0d841c40cfce0f2bd5.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:38:50'); +INSERT INTO `sys_oper_log` VALUES (1628223040682721282, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628223038937890817\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/db6c5aa2543f443b82f50f09a4375fb9.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:39:58'); +INSERT INTO `sys_oper_log` VALUES (1628223061884928002, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628223052288360450\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/a3bc0bda9bfd4b77911bfb2b409e2fb4.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:40:04'); +INSERT INTO `sys_oper_log` VALUES (1628223064011440130, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/db6c5aa2543f443b82f50f09a4375fb9.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/a3bc0bda9bfd4b77911bfb2b409e2fb4.jpg\"],\"photoNameList\":[\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column \'photo_name\' at row 1\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column \'photo_name\' at row 1\n; Data truncation: Data too long for column \'photo_name\' at row 1; nested exception is com.mysql.cj.jdbc.exceptions.MysqlDataTruncation: Data truncation: Data too long for column \'photo_name\' at row 1', '2023-02-22 10:40:04'); +INSERT INTO `sys_oper_log` VALUES (1628223194429128706, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/db6c5aa2543f443b82f50f09a4375fb9.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/a3bc0bda9bfd4b77911bfb2b409e2fb4.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/db6c5aa2543f443b82f50f09a4375fb9.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/a3bc0bda9bfd4b77911bfb2b409e2fb4.jpg\"],\"photoNameList\":[\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\",\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628223193267306497\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628223193267306497\' for key \'PRIMARY\'\n; Duplicate entry \'1628223193267306497\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628223193267306497\' for key \'PRIMARY\'', '2023-02-22 10:40:35'); +INSERT INTO `sys_oper_log` VALUES (1628223279934210050, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628223278189379585\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/22fe7a29498949e09f3d430a8ffe5683.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:40:56'); +INSERT INTO `sys_oper_log` VALUES (1628223284568915969, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/db6c5aa2543f443b82f50f09a4375fb9.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/a3bc0bda9bfd4b77911bfb2b409e2fb4.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/db6c5aa2543f443b82f50f09a4375fb9.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/a3bc0bda9bfd4b77911bfb2b409e2fb4.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/22fe7a29498949e09f3d430a8ffe5683.jpg\"],\"photoNameList\":[\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\",\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\",\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628223282765365250\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628223282765365250\' for key \'PRIMARY\'\n; Duplicate entry \'1628223282765365250\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628223282765365250\' for key \'PRIMARY\'', '2023-02-22 10:40:57'); +INSERT INTO `sys_oper_log` VALUES (1628226166626189313, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628226164214464514\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/6ac23306ff0b464fa2dd90b4df912b97.jpg\",\"fileName\":\"俄勒冈州,太平洋城,岩石,海边风景4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:52:24'); +INSERT INTO `sys_oper_log` VALUES (1628226171562885121, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/6ac23306ff0b464fa2dd90b4df912b97.jpg\"],\"photoNameList\":[\"俄勒冈州,太平洋城,岩石,海边风景4K壁纸_千叶网.jpg\"]}', '', 1, 'Index: 1, Size: 1', '2023-02-22 10:52:25'); +INSERT INTO `sys_oper_log` VALUES (1628226232476762113, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/6ac23306ff0b464fa2dd90b4df912b97.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/6ac23306ff0b464fa2dd90b4df912b97.jpg\"],\"photoNameList\":[\"俄勒冈州,太平洋城,岩石,海边风景4K壁纸_千叶网.jpg\",\"俄勒冈州,太平洋城,岩石,海边风景4K壁纸_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628226231377854465\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628226231377854465\' for key \'PRIMARY\'\n; Duplicate entry \'1628226231377854465\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628226231377854465\' for key \'PRIMARY\'', '2023-02-22 10:52:39'); +INSERT INTO `sys_oper_log` VALUES (1628227390897389570, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628227384710791169\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/3a73a6bf2b894514be30775b47700509.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 10:57:16'); +INSERT INTO `sys_oper_log` VALUES (1628227402175873026, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628227399860617217\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/7b31b62304844f3891085a21a418543d.jpeg\",\"fileName\":\"边境地区_千叶网.jpeg\"}}', 0, '', '2023-02-22 10:57:18'); +INSERT INTO `sys_oper_log` VALUES (1628227409524293634, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/3a73a6bf2b894514be30775b47700509.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/7b31b62304844f3891085a21a418543d.jpeg\"],\"photoNameList\":[\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\",\"边境地区_千叶网.jpeg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628227407846572033\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628227407846572033\' for key \'PRIMARY\'\n; Duplicate entry \'1628227407846572033\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628227407846572033\' for key \'PRIMARY\'', '2023-02-22 10:57:20'); +INSERT INTO `sys_oper_log` VALUES (1628227994419986434, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628227992486412290\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/f662bdf7bb7f4ba3bdb14e2a37214c8b.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-22 10:59:40'); +INSERT INTO `sys_oper_log` VALUES (1628228014850441218, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628228013881556994\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/e0c6b69bbdd34c0882ee0b307a24429e.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-22 10:59:44'); +INSERT INTO `sys_oper_log` VALUES (1628228103237009409, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/f662bdf7bb7f4ba3bdb14e2a37214c8b.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/e0c6b69bbdd34c0882ee0b307a24429e.jpg\"],\"photoNameList\":[\"t.jpg\",\"windows10窗口4k高清壁纸图片_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628228101492178945\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628228101492178945\' for key \'PRIMARY\'\n; Duplicate entry \'1628228101492178945\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628228101492178945\' for key \'PRIMARY\'', '2023-02-22 11:00:05'); +INSERT INTO `sys_oper_log` VALUES (1628228363808145410, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628228362709237761\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/d34fe4be5c7642fe9963741f3440e353.jpg\",\"fileName\":\"迪拜城市风光3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:01:08'); +INSERT INTO `sys_oper_log` VALUES (1628228364126912513, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628228362386276354\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/a83ec820c90f4d7b9f266723ec5a2566.jpeg\",\"fileName\":\"动画,动画,RWBY,RubyRose,角色_千叶网.jpeg\"}}', 0, '', '2023-02-22 11:01:08'); +INSERT INTO `sys_oper_log` VALUES (1628228480300744706, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/a83ec820c90f4d7b9f266723ec5a2566.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/22/d34fe4be5c7642fe9963741f3440e353.jpg\"],\"photoNameList\":[\"动画,动画,RWBY,RubyRose,角色_千叶网.jpeg\",\"迪拜城市风光3440x1440壁纸_千叶网.jpg\"]}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628228462940520450\' for key \'PRIMARY\'\r\n### The error may exist in com/zhi/blog/mapper/PhotoMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.PhotoMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_photo ( id, album_id, photo_name, photo_src, create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ? )\r\n### Cause: java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628228462940520450\' for key \'PRIMARY\'\n; Duplicate entry \'1628228462940520450\' for key \'PRIMARY\'; nested exception is java.sql.SQLIntegrityConstraintViolationException: Duplicate entry \'1628228462940520450\' for key \'PRIMARY\'', '2023-02-22 11:01:35'); +INSERT INTO `sys_oper_log` VALUES (1628228862796132354, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628228860044668929\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/b5c839687e684804804db2c34c99f20e.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:03:07'); +INSERT INTO `sys_oper_log` VALUES (1628228862796132355, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628228860044668930\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/0a32aa77c00844f190c7cc45e522427d.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:03:07'); +INSERT INTO `sys_oper_log` VALUES (1628228871117631490, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/b5c839687e684804804db2c34c99f20e.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/0a32aa77c00844f190c7cc45e522427d.jpg\"],\"photoNameList\":[\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\",\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"]}', '', 1, 'Index: 2, Size: 2', '2023-02-22 11:03:09'); +INSERT INTO `sys_oper_log` VALUES (1628230553327144962, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628230551032860676\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/187bd45165c245e5a8a19f5428b30aed.jpg\",\"fileName\":\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:09:50'); +INSERT INTO `sys_oper_log` VALUES (1628230553327144963, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628230551032860674\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/58b44e5755cf460bb9078489d7175e97.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:09:50'); +INSERT INTO `sys_oper_log` VALUES (1628230553327144964, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628230551032860675\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/c170272f435d4a5caea755eea38088f7.jpg\",\"fileName\":\"超人总动员23440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:09:50'); +INSERT INTO `sys_oper_log` VALUES (1628230568074317826, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628230565687758849\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/a4a99e1f28e64743bd6e95d2ea59abb0.jpg\",\"fileName\":\"澳大利亚,艾尔斯岩,星空3440x1440高清壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:09:53'); +INSERT INTO `sys_oper_log` VALUES (1628230573682102273, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/187bd45165c245e5a8a19f5428b30aed.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/58b44e5755cf460bb9078489d7175e97.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/c170272f435d4a5caea755eea38088f7.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/a4a99e1f28e64743bd6e95d2ea59abb0.jpg\"],\"photoNameList\":[\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\",\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\",\"超人总动员23440x1440壁纸_千叶网.jpg\",\"澳大利亚,艾尔斯岩,星空3440x1440高清壁纸_千叶网.jpg\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 11:09:54'); +INSERT INTO `sys_oper_log` VALUES (1628238172829814786, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628238171089178625\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/56cab13b983b422080c02e2efeb16852.jpg\",\"fileName\":\"冰岛的环路4K风景壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:40:06'); +INSERT INTO `sys_oper_log` VALUES (1628238172829814787, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628238171152093185\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/8516668007e3490e9b7c61eab483d066.png\",\"fileName\":\"超宽,空间,蓝色_千叶网.png\"}}', 0, '', '2023-02-22 11:40:06'); +INSERT INTO `sys_oper_log` VALUES (1628238173215690753, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628238170636193794\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/cb01806c847941f1b9666a338041fe2c.jpeg\",\"fileName\":\"超宽,景观,自然,空间_千叶网.jpeg\"}}', 0, '', '2023-02-22 11:40:06'); +INSERT INTO `sys_oper_log` VALUES (1628238173282799617, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628238170829131778\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/1c09448f90d142bfb78c3e513b748af7.jpg\",\"fileName\":\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:40:06'); +INSERT INTO `sys_oper_log` VALUES (1628238173345714177, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628238170959155201\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/bcfb1cfd8d3c411e8214bb5cdb1afe3e.jpg\",\"fileName\":\"超人总动员23440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 11:40:06'); +INSERT INTO `sys_oper_log` VALUES (1628238178441793538, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/22/cb01806c847941f1b9666a338041fe2c.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/22/1c09448f90d142bfb78c3e513b748af7.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/bcfb1cfd8d3c411e8214bb5cdb1afe3e.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/56cab13b983b422080c02e2efeb16852.jpg\",\"http://127.0.0.1:9000/blog/2023/02/22/8516668007e3490e9b7c61eab483d066.png\"],\"photoNameList\":[\"超宽,景观,自然,空间_千叶网.jpeg\",\"沉沦螺旋_荷鲁斯站Downward,Spiral_,Horus,Station3440x1440壁纸_千叶网.jpg\",\"超人总动员23440x1440壁纸_千叶网.jpg\",\"冰岛的环路4K风景壁纸_千叶网.jpg\",\"超宽,空间,蓝色_千叶网.png\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 11:40:08'); +INSERT INTO `sys_oper_log` VALUES (1628255854547472386, '照片管理', 3, 'com.zhi.blog.controller.PhotoController.remove()', 'DELETE', 1, 'admin', '', '/photo/photo/1628223193267306497', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 12:50:22'); +INSERT INTO `sys_oper_log` VALUES (1628255886302547969, '照片管理', 3, 'com.zhi.blog.controller.PhotoController.remove()', 'DELETE', 1, 'admin', '', '/photo/photo/1628223193267306497,1628228101492178945,1628227407846572033', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 12:50:29'); +INSERT INTO `sys_oper_log` VALUES (1628256535903768577, '照片管理', 3, 'com.zhi.blog.controller.PhotoController.remove()', 'DELETE', 1, 'admin', '', '/photo/photo/1628223193267306497,1628228101492178945,1628227407846572033,1628238176831180803,1628230572654497795', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 12:53:04'); +INSERT INTO `sys_oper_log` VALUES (1628256591251804161, '照片管理', 3, 'com.zhi.blog.controller.PhotoController.remove()', 'DELETE', 1, 'admin', '', '/photo/photo/1628223193267306497,1628228101492178945,1628227407846572033,1628238176831180803,1628230572654497795,1628238176831180802,1628230572608360450', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 12:53:18'); +INSERT INTO `sys_oper_log` VALUES (1628267546195005441, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.edit()', 'PUT', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1628228462940520450\",\"albumId\":\"1627860336587612162\",\"photoName\":\"11\",\"photoDesc\":\"11\",\"photoSrc\":\"http://127.0.0.1:9000/blog/2023/02/22/a83ec820c90f4d7b9f266723ec5a2566.jpeg\",\"isDelete\":0}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 13:36:49'); +INSERT INTO `sys_oper_log` VALUES (1628267619872149505, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.edit()', 'PUT', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1628228462940520450\",\"albumId\":\"1627860336587612162\",\"photoName\":\"11\",\"photoDesc\":\"没有描述·\",\"photoSrc\":\"http://127.0.0.1:9000/blog/2023/02/22/a83ec820c90f4d7b9f266723ec5a2566.jpeg\",\"isDelete\":0}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 13:37:07'); +INSERT INTO `sys_oper_log` VALUES (1628268476911063041, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628268475103318017\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/9e7bd207ef9d4c819da26f9e0d61cbaa.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 13:40:31'); +INSERT INTO `sys_oper_log` VALUES (1628268482581762049, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1628268480258117634\",\"albumName\":\"猪猪·\",\"albumDesc\":\"猪猪·\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/22/9e7bd207ef9d4c819da26f9e0d61cbaa.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 13:40:33'); +INSERT INTO `sys_oper_log` VALUES (1628389240754794497, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.editPhotoAlbum()', 'PUT', 1, 'admin', '', '/photo/photo/album', '4.2.2.2', ' ', '{\"ids\":[\"1628228462940520450\"],\"albumid\":\"1628268480258117634\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:40:24'); +INSERT INTO `sys_oper_log` VALUES (1628389299714125825, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.editPhotoAlbum()', 'PUT', 1, 'admin', '', '/photo/photo/album', '4.2.2.2', ' ', '{\"ids\":[\"1628228462940520450\",\"1628228868731072514\",\"1628228868793987073\"],\"albumid\":\"1628268480258117634\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:40:38'); +INSERT INTO `sys_oper_log` VALUES (1628389422183608322, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628389419792855041\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/22/07d2835ba83e4dc782fa04899be5ce4b.jpg\",\"fileName\":\"Niyas,CK,India,3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-22 21:41:07'); +INSERT INTO `sys_oper_log` VALUES (1628389425937510401, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1628389422913417218\",\"albumName\":\"啦啦啦啦\",\"albumDesc\":\"拉拉\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/22/07d2835ba83e4dc782fa04899be5ce4b.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:41:08'); +INSERT INTO `sys_oper_log` VALUES (1628389467507257345, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.editPhotoAlbum()', 'PUT', 1, 'admin', '', '/photo/photo/album', '4.2.2.2', ' ', '{\"ids\":[\"1628230572654497796\",\"1628238176831180804\"],\"albumid\":\"1628389422913417218\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:41:18'); +INSERT INTO `sys_oper_log` VALUES (1628389505738338306, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.editPhotoAlbum()', 'PUT', 1, 'admin', '', '/photo/photo/album', '4.2.2.2', ' ', '{\"ids\":[\"1628238176831180804\"],\"albumid\":\"1627860336587612162\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:41:27'); +INSERT INTO `sys_oper_log` VALUES (1628389624537804801, '照片管理', 2, 'com.zhi.blog.controller.PhotoController.edit()', 'PUT', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1628228868793987073\",\"albumId\":\"1628268480258117634\",\"photoName\":\"奥日和黑暗森林\",\"photoDesc\":\"666\",\"photoSrc\":\"http://127.0.0.1:9000/blog/2023/02/22/0a32aa77c00844f190c7cc45e522427d.jpg\",\"isDelete\":0}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:41:55'); +INSERT INTO `sys_oper_log` VALUES (1628390877514821634, '菜单管理', 2, 'com.zhi.web.controller.system.SysMenuController.edit()', 'PUT', 1, 'admin', '', '/system/menu', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-02-21 19:41:06\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-22 21:46:53\",\"parentName\":null,\"parentId\":\"1627642998340730881\",\"children\":[],\"menuId\":\"1627996831193526274\",\"menuName\":\"照片管理\",\"orderNum\":2,\"path\":\"photo\",\"component\":\"album/album/Photo\",\"queryParam\":\"\",\"isFrame\":\"1\",\"isCache\":\"0\",\"menuType\":\"C\",\"visible\":\"1\",\"status\":\"0\",\"icon\":\"eye-open\",\"remark\":\"\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-22 21:46:54'); +INSERT INTO `sys_oper_log` VALUES (1628648986514558978, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.edit()', 'PUT', 1, 'admin', '', '/system/role', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-23 14:52:31\",\"roleId\":3,\"roleName\":\"本部门及以下\",\"roleKey\":\"test1\",\"roleSort\":3,\"dataScope\":\"4\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":null,\"flag\":false,\"menuIds\":[1,108,501,\"1610972802922405889\",\"1610973263779946497\",\"1611336461808898048\",\"1611336461808898049\",\"1611336461808898050\",\"1611336461808898051\",\"1611336461808898052\",\"1611336461808898053\",\"1611613727679938560\",\"1611613727679938561\",\"1611613727679938562\",\"1611613727679938563\",\"1611613727679938564\",\"1611613727679938565\",\"1611975928588574720\",\"1611975928588574721\",\"1611975928588574722\",\"1611975928588574723\",\"1611975928588574724\",\"1611975928588574725\",100,1001,1002,1003,1004,1005,1006,1007,101,1008,1009,1010,1011,1012,102,1013,1014,1015,1016,103,1017,1018,1019,1020,104,1021,1022,1023,1024,1025,105,1026,1027,1028,1029,1030,106,1031,1032,1033,1034,1035,107,1036,1037,1038,1039,500,1040,1041,1042,1043,1044,1045,5,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511],\"deptIds\":null,\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 14:52:32'); +INSERT INTO `sys_oper_log` VALUES (1628649588195856386, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.dataScope()', 'PUT', 1, 'admin', '', '/system/role/dataScope', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-23 14:54:54\",\"roleId\":3,\"roleName\":\"本部门及以下\",\"roleKey\":\"test1\",\"roleSort\":3,\"dataScope\":\"4\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":[],\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 14:54:55'); +INSERT INTO `sys_oper_log` VALUES (1628649615035207682, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.dataScope()', 'PUT', 1, 'admin', '', '/system/role/dataScope', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-23 14:55:01\",\"roleId\":4,\"roleName\":\"仅本人\",\"roleKey\":\"test2\",\"roleSort\":4,\"dataScope\":\"5\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":[],\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 14:55:02'); +INSERT INTO `sys_oper_log` VALUES (1628740823380168705, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628740820213469186\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/9383112a6f184478bc19d9c599d838ed.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-23 20:57:27'); +INSERT INTO `sys_oper_log` VALUES (1628740823380168706, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628740820213469187\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/f64fce4f33d841c8a243b88dc1de9b38.jpeg\",\"fileName\":\"thelastofus,apocalyptic_千叶网.jpeg\"}}', 0, '', '2023-02-23 20:57:27'); +INSERT INTO `sys_oper_log` VALUES (1628740823380168707, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628740820213469185\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/9e959af95ac1495891a20b1c5ae596af.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-23 20:57:27'); +INSERT INTO `sys_oper_log` VALUES (1628740827905822721, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1627860336587612162\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/23/f64fce4f33d841c8a243b88dc1de9b38.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/23/9e959af95ac1495891a20b1c5ae596af.jpg\",\"http://127.0.0.1:9000/blog/2023/02/23/9383112a6f184478bc19d9c599d838ed.jpg\"],\"photoNameList\":[\"thelastofus,apocalyptic_千叶网.jpeg\",\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\",\"t.jpg\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 20:57:29'); +INSERT INTO `sys_oper_log` VALUES (1628740925972844546, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1627860336587612162', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 20:57:52'); +INSERT INTO `sys_oper_log` VALUES (1628741387090432001, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628741384812924930\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/a243f8d6f4624c77b0a5df4eaa5199b4.jpeg\",\"fileName\":\"scarlettjohansson,抽象,doubleexposure,undertheskin_千叶网.jpeg\"}}', 0, '', '2023-02-23 20:59:42'); +INSERT INTO `sys_oper_log` VALUES (1628741387090432002, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628741384812924931\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/2eca7b1342d041f28d27caf5c33f8bee.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-23 20:59:42'); +INSERT INTO `sys_oper_log` VALUES (1628741387090432003, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628741384812924929\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/af9bed20744f4ebcacb08ee7e7fef96e.jpeg\",\"fileName\":\"Spider,Man,MaviC漫画,漫画,蜘蛛,超级英雄,标志,黑暗_千叶网.jpeg\"}}', 0, '', '2023-02-23 20:59:42'); +INSERT INTO `sys_oper_log` VALUES (1628741393155395586, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1628268480258117634\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/23/2eca7b1342d041f28d27caf5c33f8bee.jpg\",\"http://127.0.0.1:9000/blog/2023/02/23/af9bed20744f4ebcacb08ee7e7fef96e.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/23/a243f8d6f4624c77b0a5df4eaa5199b4.jpeg\"],\"photoNameList\":[\"t.jpg\",\"Spider,Man,MaviC漫画,漫画,蜘蛛,超级英雄,标志,黑暗_千叶网.jpeg\",\"scarlettjohansson,抽象,doubleexposure,undertheskin_千叶网.jpeg\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 20:59:43'); +INSERT INTO `sys_oper_log` VALUES (1628741452232167426, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1628268480258117634', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 20:59:57'); +INSERT INTO `sys_oper_log` VALUES (1628742005561524226, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742002663260163\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/9d7b2483cee54a709875938f87edafc7.jpg\",\"fileName\":\"Life,is,Strange,23440x1440带鱼屏壁纸_千叶网.jpg\"}}', 0, '', '2023-02-23 21:02:09'); +INSERT INTO `sys_oper_log` VALUES (1628742005561524227, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742002663260162\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/cfbfb6e32b064237a0174ba5b4a7ac03.jpeg\",\"fileName\":\"LOL娜美3440x1440壁纸_千叶网.jpeg\"}}', 0, '', '2023-02-23 21:02:09'); +INSERT INTO `sys_oper_log` VALUES (1628742005561524228, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742002663260161\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/db6e8324ed9e43639aa2d1e2ce1040d2.jpg\",\"fileName\":\"LOL新版皮肤稻草人联合王国,费德提克3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-23 21:02:09'); +INSERT INTO `sys_oper_log` VALUES (1628742008275238913, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1628389422913417218\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/23/cfbfb6e32b064237a0174ba5b4a7ac03.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/23/db6e8324ed9e43639aa2d1e2ce1040d2.jpg\",\"http://127.0.0.1:9000/blog/2023/02/23/9d7b2483cee54a709875938f87edafc7.jpg\"],\"photoNameList\":[\"LOL娜美3440x1440壁纸_千叶网.jpeg\",\"LOL新版皮肤稻草人联合王国,费德提克3440x1440壁纸_千叶网.jpg\",\"Life,is,Strange,23440x1440带鱼屏壁纸_千叶网.jpg\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 21:02:10'); +INSERT INTO `sys_oper_log` VALUES (1628742148885086210, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1628389422913417218', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 21:02:44'); +INSERT INTO `sys_oper_log` VALUES (1628742503777820673, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742501022162946\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/f0b43ffa8ef646c2bd53b2bc17b23096.jpg\",\"fileName\":\"windows10窗口4k高清壁纸图片_千叶网.jpg\"}}', 0, '', '2023-02-23 21:04:08'); +INSERT INTO `sys_oper_log` VALUES (1628742505455542273, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1628742503907844097\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/23/f0b43ffa8ef646c2bd53b2bc17b23096.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 21:04:09'); +INSERT INTO `sys_oper_log` VALUES (1628742527697936386, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742525885997058\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/c27113b003b84070bc4142cfbe81fe87.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-23 21:04:14'); +INSERT INTO `sys_oper_log` VALUES (1628742528020897794, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742525693059074\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/8117dbbf17ac45038383c449346f1642.jpeg\",\"fileName\":\"thelastofus,apocalyptic_千叶网.jpeg\"}}', 0, '', '2023-02-23 21:04:14'); +INSERT INTO `sys_oper_log` VALUES (1628742528083812354, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1628742525755973633\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/23/05a282c6e364474a802f29bcf42a48b1.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-23 21:04:14'); +INSERT INTO `sys_oper_log` VALUES (1628742532349419521, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '4.2.2.2', ' ', '{\"albumid\":\"1628742503907844097\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/02/23/8117dbbf17ac45038383c449346f1642.jpeg\",\"http://127.0.0.1:9000/blog/2023/02/23/05a282c6e364474a802f29bcf42a48b1.jpg\",\"http://127.0.0.1:9000/blog/2023/02/23/c27113b003b84070bc4142cfbe81fe87.jpg\"],\"photoNameList\":[\"thelastofus,apocalyptic_千叶网.jpeg\",\"t.jpg\",\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 21:04:15'); +INSERT INTO `sys_oper_log` VALUES (1628742589459062786, '相册管理', 3, 'com.zhi.blog.controller.AlbumController.remove()', 'DELETE', 1, 'admin', '', '/album/album/1628742503907844097', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-23 21:04:29'); +INSERT INTO `sys_oper_log` VALUES (1629470541016477698, '用户管理', 2, 'com.zhi.web.controller.system.SysUserController.edit()', 'PUT', 1, 'admin', '', '/system/user', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:34\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-25 21:17:05\",\"userId\":4,\"deptId\":104,\"userName\":\"test1\",\"nickName\":\"仅本人 密码666666\",\"userType\":\"sys_user\",\"email\":\"\",\"phonenumber\":\"\",\"sex\":\"0\",\"avatar\":\"http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg\",\"status\":\"0\",\"delFlag\":\"0\",\"loginIp\":\"4.2.2.2\",\"loginDate\":\"2023-02-23 15:05:27\",\"remark\":null,\"intro\":null,\"webSite\":null,\"dept\":{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"parentName\":null,\"parentId\":100,\"children\":[],\"deptId\":104,\"deptName\":\"芝士团\",\"orderNum\":1,\"leader\":\"ftz\",\"phone\":null,\"email\":null,\"status\":\"0\",\"delFlag\":null,\"ancestors\":\"0,100\"},\"roles\":[{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"roleId\":4,\"roleName\":\"仅本人\",\"roleKey\":\"test2\",\"roleSort\":4,\"dataScope\":\"5\",\"menuCheckStrictly\":null,\"deptCheckStrictly\":null,\"status\":\"0\",\"delFlag\":null,\"remark\":null,\"flag\":false,\"menuIds\":null,\"deptIds\":null,\"permissions\":null,\"admin\":false}],\"roleIds\":[2],\"postIds\":[],\"roleId\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-25 21:17:06'); +INSERT INTO `sys_oper_log` VALUES (1629470599531212801, '角色管理', 2, 'com.zhi.web.controller.system.SysRoleController.edit()', 'PUT', 1, 'admin', '', '/system/role', '4.2.2.2', ' ', '{\"createBy\":\"admin\",\"createTime\":\"2023-01-05 19:54:19\",\"updateBy\":\"admin\",\"updateTime\":\"2023-02-25 21:17:19\",\"roleId\":2,\"roleName\":\"普通角色\",\"roleKey\":\"common\",\"roleSort\":2,\"dataScope\":\"2\",\"menuCheckStrictly\":true,\"deptCheckStrictly\":true,\"status\":\"0\",\"delFlag\":\"0\",\"remark\":\"普通角色\",\"flag\":false,\"menuIds\":[2,109,1046,1047,1048,113,112,3,114,115,1055,1056,1058,1057,1059,1060],\"deptIds\":null,\"permissions\":null,\"admin\":false}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-25 21:17:20'); +INSERT INTO `sys_oper_log` VALUES (1630182479073746945, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1627852985965080577\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:26:05'); +INSERT INTO `sys_oper_log` VALUES (1630182551253524481, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1627852985965080577\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:26:22'); +INSERT INTO `sys_oper_log` VALUES (1630182639010947073, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1630182637203202050\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/27/c1ed44bc66de4d648209d14b9d31bd69.jpg\",\"fileName\":\"The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-27 20:26:43'); +INSERT INTO `sys_oper_log` VALUES (1630182641976320001, '相册管理', 1, 'com.zhi.blog.controller.AlbumController.add()', 'POST', 1, 'admin', '', '/album/album', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":\"1630182639979831298\",\"albumName\":\"测试\",\"albumDesc\":\"测试\",\"albumCover\":\"http://127.0.0.1:9000/blog/2023/02/27/c1ed44bc66de4d648209d14b9d31bd69.jpg\",\"isDelete\":null,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:26:44'); +INSERT INTO `sys_oper_log` VALUES (1630183772261556226, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1627852985965080577', '4.2.2.2', ' ', '{}', '{\"code\":500,\"msg\":\"操作失败\",\"data\":null}', 0, '', '2023-02-27 20:31:13'); +INSERT INTO `sys_oper_log` VALUES (1630183790976540673, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1630183789298819074\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/27/011af11410064e15bae1670d8b015fa2.jpg\",\"fileName\":\"t.jpg\"}}', 0, '', '2023-02-27 20:31:18'); +INSERT INTO `sys_oper_log` VALUES (1630183793304379394, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":139,\"userId\":1,\"categoryId\":216,\"categoryName\":\"正式\",\"tagNameList\":[\"测试\",\"html\"],\"articleCover\":\"1630183789298819074\",\"articleTitle\":\"第二篇测试\",\"articleContent\":\"test上传\",\"type\":1,\"originalUrl\":\"\",\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:31:18'); +INSERT INTO `sys_oper_log` VALUES (1630183839030681601, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1630183837352960001\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/27/7a96413957ea4ff998dc2a62b1246c7d.jpg\",\"fileName\":\"奥日和黑暗森林3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-27 20:31:29'); +INSERT INTO `sys_oper_log` VALUES (1630183841614372865, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1630183837352960001\",\"articleTitle\":\"新的vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:31:30'); +INSERT INTO `sys_oper_log` VALUES (1630188084169646082, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1630188081078444034\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/27/03d15fc042af4b9c8deafe3496aa2c5e.jpg\",\"fileName\":\"奥日与鬼火意志Ori,and,the,Will,of,the,Wisps3440x1440壁纸_千叶网.jpg\"}}', 0, '', '2023-02-27 20:48:21'); +INSERT INTO `sys_oper_log` VALUES (1630188087009189889, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"pageName\":\"首页\",\"pageLabel\":\"home\",\"pageCover\":\"1630188081078444034\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:48:22'); +INSERT INTO `sys_oper_log` VALUES (1630188145213546498, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/154', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:48:36'); +INSERT INTO `sys_oper_log` VALUES (1630188157280559106, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/153', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:48:39'); +INSERT INTO `sys_oper_log` VALUES (1630188932140474369, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/139', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-27 20:51:44'); +INSERT INTO `sys_oper_log` VALUES (1630392958811389953, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1630392957024616450\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/28/37b8cdb431a3472e83252aa67896e497.jpg\",\"fileName\":\"奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg\"}}', 0, '', '2023-02-28 10:22:27'); +INSERT INTO `sys_oper_log` VALUES (1630392967489404930, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 10:22:29'); +INSERT INTO `sys_oper_log` VALUES (1630393448018231298, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:24:24'); +INSERT INTO `sys_oper_log` VALUES (1630393950961418241, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:26:24'); +INSERT INTO `sys_oper_log` VALUES (1630394204989440002, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:27:24'); +INSERT INTO `sys_oper_log` VALUES (1630394994948849665, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:30:33'); +INSERT INTO `sys_oper_log` VALUES (1630395053526499329, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:30:47'); +INSERT INTO `sys_oper_log` VALUES (1630395132178087938, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', 'XX XX', '{}', '', 1, '', '2023-02-28 10:31:05'); +INSERT INTO `sys_oper_log` VALUES (1630396076550795266, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '4.2.2.2', ' ', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1630396074092933122\",\"url\":\"http://127.0.0.1:9000/blog/2023/02/28/8815c9b53d3f442bb096b7c400306ace.jpeg\",\"fileName\":\"thelastofus,apocalyptic_千叶网.jpeg\"}}', 0, '', '2023-02-28 10:34:51'); +INSERT INTO `sys_oper_log` VALUES (1630396083588837377, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":156,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1630396074092933122\",\"articleTitle\":\"123\",\"articleContent\":\"123\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 10:34:52'); +INSERT INTO `sys_oper_log` VALUES (1630396224374845441, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/156', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:35:26'); +INSERT INTO `sys_oper_log` VALUES (1630397493181267970, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:40:28'); +INSERT INTO `sys_oper_log` VALUES (1630397598798036993, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 10:40:54'); +INSERT INTO `sys_oper_log` VALUES (1630398584815992833, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":null,\"tagNameList\":[],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-02-28 10:44:49'); +INSERT INTO `sys_oper_log` VALUES (1630398696531279874, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":null,\"tagNameList\":[],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-02-28 10:45:15'); +INSERT INTO `sys_oper_log` VALUES (1630398768765583362, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":null,\"tagNameList\":[],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-02-28 10:45:32'); +INSERT INTO `sys_oper_log` VALUES (1630408430080606210, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":156,\"userId\":1,\"categoryId\":1,\"categoryName\":null,\"tagNameList\":[],\"articleCover\":\"1630396074092933122\",\"articleTitle\":\"123\",\"articleContent\":\"123\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-02-28 11:23:56'); +INSERT INTO `sys_oper_log` VALUES (1630409546956660738, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '', 1, '\r\n### Error updating database. Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\r\n### The error may exist in com/zhi/blog/mapper/CategoryMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CategoryMapper.insert-Inline\r\n### The error occurred while setting parameters\r\n### SQL: INSERT INTO blog_category ( create_by, create_time, update_by, update_time ) VALUES ( ?, ?, ?, ? )\r\n### Cause: java.sql.SQLException: Field \'category_name\' doesn\'t have a default value\n; Field \'category_name\' doesn\'t have a default value; nested exception is java.sql.SQLException: Field \'category_name\' doesn\'t have a default value', '2023-02-28 11:28:22'); +INSERT INTO `sys_oper_log` VALUES (1630409936582221825, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":156,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1630396074092933122\",\"articleTitle\":\"123\",\"articleContent\":\"123\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 11:29:55'); +INSERT INTO `sys_oper_log` VALUES (1630409978089054210, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"springboot\"],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 11:30:05'); +INSERT INTO `sys_oper_log` VALUES (1630410976459251713, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 11:34:03'); +INSERT INTO `sys_oper_log` VALUES (1630411226573975553, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 11:35:03'); +INSERT INTO `sys_oper_log` VALUES (1630412037681074177, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 11:38:16'); +INSERT INTO `sys_oper_log` VALUES (1630412786334973953, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 11:41:15'); +INSERT INTO `sys_oper_log` VALUES (1630412974386696193, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 11:41:59'); +INSERT INTO `sys_oper_log` VALUES (1630415741666840577, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 11:52:59'); +INSERT INTO `sys_oper_log` VALUES (1630417219538243585, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 11:58:51'); +INSERT INTO `sys_oper_log` VALUES (1630417759764598786, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 12:01:00'); +INSERT INTO `sys_oper_log` VALUES (1630420154867257346, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 12:10:31'); +INSERT INTO `sys_oper_log` VALUES (1630522633269280769, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 18:57:44'); +INSERT INTO `sys_oper_log` VALUES (1630522977135132673, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 18:59:06'); +INSERT INTO `sys_oper_log` VALUES (1630523886107901954, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 19:02:43'); +INSERT INTO `sys_oper_log` VALUES (1630539411819073538, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 20:04:24'); +INSERT INTO `sys_oper_log` VALUES (1630539622809341954, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 20:05:15'); +INSERT INTO `sys_oper_log` VALUES (1630539886643646466, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 20:06:18'); +INSERT INTO `sys_oper_log` VALUES (1630539952930426882, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, '', '2023-02-28 20:06:33'); +INSERT INTO `sys_oper_log` VALUES (1630540776121421826, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '4.2.2.2', ' ', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":155,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1630392957024616450\",\"articleTitle\":\"测试删除\",\"articleContent\":\"测试删除\",\"type\":2,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 20:09:50'); +INSERT INTO `sys_oper_log` VALUES (1630540810149810178, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '', 1, 'nested exception is org.apache.ibatis.exceptions.PersistenceException: \r\n### Error updating database. Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: DELETE FROM blog_comment WHERE id IN ( )\r\n### The error may exist in com/zhi/blog/mapper/CommentMapper.java (best guess)\r\n### The error may involve com.zhi.blog.mapper.CommentMapper.deleteBatchIds\r\n### The error occurred while executing an update\r\n### Cause: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Failed to process, Error SQL: DELETE FROM blog_comment WHERE id IN ( )', '2023-02-28 20:09:58'); +INSERT INTO `sys_oper_log` VALUES (1630541699480567810, '文章列表', 3, 'com.zhi.blog.controller.ArticleController.remove()', 'DELETE', 1, 'admin', '', '/article/article/155', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 20:13:30'); +INSERT INTO `sys_oper_log` VALUES (1630543167365357569, '说说管理', 3, 'com.zhi.blog.controller.TalkController.remove()', 'DELETE', 1, 'admin', '', '/talk/talk/59', '4.2.2.2', ' ', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-02-28 20:19:20'); +INSERT INTO `sys_oper_log` VALUES (1633693827350958081, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1633693827288043522\",\"url\":\"http://127.0.0.1:9000/blog/2023/03/09/bf0032f388f249cd8d47b81ed24a26a4.jpeg\",\"fileName\":\"LOL娜美3440x1440壁纸_千叶网.jpeg\"}}', 0, '', '2023-03-09 12:58:56'); +INSERT INTO `sys_oper_log` VALUES (1633693831679479809, '照片管理', 1, 'com.zhi.blog.controller.PhotoController.add()', 'POST', 1, 'admin', '', '/photo/photo', '127.0.0.1', '内网IP', '{\"albumid\":\"1630182639979831298\",\"photoUrlList\":[\"http://127.0.0.1:9000/blog/2023/03/09/bf0032f388f249cd8d47b81ed24a26a4.jpeg\"],\"photoNameList\":[\"LOL娜美3440x1440壁纸_千叶网.jpeg\"]}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-03-09 12:58:57'); +INSERT INTO `sys_oper_log` VALUES (1647072075401154562, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1630183837352960001', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-15 10:59:19'); +INSERT INTO `sys_oper_log` VALUES (1647072122532548609, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1647072122465439746\",\"url\":\"http://127.0.0.1:9000/blog/2023/04/15/49170847943248e4b713989ddd13057f.jpg\",\"fileName\":\"Riffelsee里弗尔湖3440x1440风景壁纸_千叶网.jpg\"}}', 0, '', '2023-04-15 10:59:30'); +INSERT INTO `sys_oper_log` VALUES (1647072128526209025, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1647072122465439746\",\"articleTitle\":\"新的vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-15 10:59:31'); +INSERT INTO `sys_oper_log` VALUES (1647486327500865537, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[The Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 1756563B632B1530; S3 Extended Request ID: aeaa3630-511a-428b-86d5-2c983a4507cf; Proxy: null)]', '2023-04-16 14:25:24'); +INSERT INTO `sys_oper_log` VALUES (1647487165757685761, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":\"PTkrtTWYYmGcWh4R\",\"secretKey\":\"TPbwHM7lBNAnCuX7FD9xjuYokn2j9T5Z\",\"bucketName\":\"blog\",\"prefix\":\"\",\"endpoint\":\"127.0.0.1:9000\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"0\",\"region\":\"\",\"ext1\":\"\",\"remark\":\"\",\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-16 14:28:44'); +INSERT INTO `sys_oper_log` VALUES (1647487217796415490, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '', 1, '创建Bucket失败, 请核对配置信息:[The Access Key Id you provided does not exist in our records. (Service: Amazon S3; Status Code: 403; Error Code: InvalidAccessKeyId; Request ID: 1756566CCFDC3408; S3 Extended Request ID: aeaa3630-511a-428b-86d5-2c983a4507cf; Proxy: null)]', '2023-04-16 14:28:56'); +INSERT INTO `sys_oper_log` VALUES (1647487626321625089, '对象存储配置', 2, 'com.zhi.web.controller.system.SysOssConfigController.edit()', 'PUT', 1, 'admin', '', '/system/oss/config', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"ossConfigId\":1,\"configKey\":\"minio\",\"accessKey\":\"05BFXRnPh5nmBEjH\",\"secretKey\":\"dZMNeKRRLZ7TheyHhvepfusURer9AWIt\",\"bucketName\":\"blog\",\"prefix\":\"\",\"endpoint\":\"127.0.0.1:9000\",\"domain\":\"\",\"isHttps\":\"N\",\"status\":\"0\",\"region\":\"\",\"ext1\":\"\",\"remark\":\"\",\"accessPolicy\":\"1\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-16 14:30:34'); +INSERT INTO `sys_oper_log` VALUES (1647487705090654209, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1647072122465439746', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-16 14:30:52'); +INSERT INTO `sys_oper_log` VALUES (1647487717145083905, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1647487717082169345\",\"url\":\"http://127.0.0.1:9000/blog/2023/04/16/dfddc05f9a9d48439599d442f2350646.jpg\",\"fileName\":\"1164338.jpg\"}}', 0, '', '2023-04-16 14:30:55'); +INSERT INTO `sys_oper_log` VALUES (1647487720047542273, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1647487717082169345\",\"articleTitle\":\"新的vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-16 14:30:56'); +INSERT INTO `sys_oper_log` VALUES (1647487909449728001, 'OSS对象存储', 3, 'com.zhi.web.controller.system.SysOssController.remove()', 'DELETE', 1, 'admin', '', '/system/oss/1630188081078444034', '127.0.0.1', '内网IP', '{}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-16 14:31:41'); +INSERT INTO `sys_oper_log` VALUES (1647487957390622722, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1647487957390622721\",\"url\":\"http://127.0.0.1:9000/blog/2023/04/16/816497bf0865489a9563f4acdafa736b.jpg\",\"fileName\":\"QQ图片20210423133304.jpg\"}}', 0, '', '2023-04-16 14:31:53'); +INSERT INTO `sys_oper_log` VALUES (1647487960939003906, '页面管理', 2, 'com.zhi.blog.controller.BlogPageController.edit()', 'PUT', 1, 'admin', '', '/page/page', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":1,\"pageName\":\"首页\",\"pageLabel\":\"home\",\"pageCover\":\"1647487957390622721\"}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-16 14:31:53'); +INSERT INTO `sys_oper_log` VALUES (1647910881796837377, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1647910881729728513\",\"url\":\"http://127.0.0.1:9000/blog/2023/04/17/fb6fdcfdf0b1426183c791fa20be4d24.jpg\",\"fileName\":\"QQ图片20210630102619.jpg\"}}', 0, '', '2023-04-17 18:32:26'); +INSERT INTO `sys_oper_log` VALUES (1647910891024306177, '文章列表', 1, 'com.zhi.blog.controller.ArticleController.add()', 'POST', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":157,\"userId\":1,\"categoryId\":1,\"categoryName\":\"默认\",\"tagNameList\":[\"默认\"],\"articleCover\":\"1647910881729728513\",\"articleTitle\":\"喜好测试\",\"articleContent\":\"喜好测试\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-17 18:32:28'); +INSERT INTO `sys_oper_log` VALUES (1647911339319906306, 'OSS对象存储', 1, 'com.zhi.web.controller.system.SysOssController.upload()', 'POST', 1, 'admin', '', '/system/oss/upload', '127.0.0.1', '内网IP', '', '{\"code\":200,\"msg\":\"操作成功\",\"data\":{\"ossId\":\"1647911339319906305\",\"url\":\"http://127.0.0.1:9000/blog/2023/04/17/c45820d458654545b92c79c6fd148311.jpg\",\"fileName\":\"1161451.jpg\"}}', 0, '', '2023-04-17 18:34:15'); +INSERT INTO `sys_oper_log` VALUES (1647911472572944385, '文章列表', 2, 'com.zhi.blog.controller.ArticleController.edit()', 'PUT', 1, 'admin', '', '/article/article', '127.0.0.1', '内网IP', '{\"createBy\":null,\"createTime\":null,\"updateBy\":null,\"updateTime\":null,\"id\":143,\"userId\":1,\"categoryId\":214,\"categoryName\":\"测试\",\"tagNameList\":[\"啦啦啦\"],\"articleCover\":\"1647487717082169345\",\"articleTitle\":\"新的vue测试\",\"articleContent\":\"# Vue中 this.$router.push 传参 及 参数接收\\n@[TOC](文章目录)\\n## 1:两种方式![Description](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法一:name跳转页面\\n\\n```js\\nthis.$router.push({name:\'anotherPage\',params:{id:1}});\\n\\n```\\n**另一页面接收参数方式:**\\n![1161451.jpg](http://127.0.0.1:9000/blog/2023/04/17/c45820d458654545b92c79c6fd148311.jpg)\\n```js\\nthis.$route.params.id\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/ee3e431c7d1f42e290cacb126494598f.png)\\n控制台展示:\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/da7e9c45e3be4ae89373ec195b0c96d7.png)\\n### 方法二:path跳转页面\\n\\n```js\\nthis.$router.push({path:\'/anotherPage\',query:{id:1}});\\n\\n```\\n![在这里插入图片描述](https://img-blog.csdnimg.cn/a54ddde315754e65977725ffc62f1e2a.png)\\n\\n\\n## 2、区别\\n### 1、path的query传参的参数会带在url后边展示在地址栏(/anotherPage?id=1),name的params传参的参数不会展示到地址栏。\\n### 2、由于动态路由也是传递params的,所以在 this.$router.push() 方法中path不能和params一起使用,否则params将无效,需要用name来指定页面。\\n\\n原文链接:https://blog.csdn.net/chenxi_li/article/details/108365779\",\"type\":1,\"originalUrl\":null,\"isDelete\":0,\"status\":1}', '{\"code\":200,\"msg\":\"操作成功\",\"data\":null}', 0, '', '2023-04-17 18:34:46'); + +-- ---------------------------- +-- Table structure for sys_oss +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oss`; +CREATE TABLE `sys_oss` ( + `oss_id` bigint(20) NOT NULL COMMENT '对象存储主键', + `file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件名', + `original_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '原名', + `file_suffix` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '文件后缀名', + `url` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'URL地址', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '上传人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新人', + `service` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'minio' COMMENT '服务商', + PRIMARY KEY (`oss_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'OSS对象存储表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_oss +-- ---------------------------- +INSERT INTO `sys_oss` VALUES (1628740820213469185, '2023/02/23/9e959af95ac1495891a20b1c5ae596af.jpg', 'The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/9e959af95ac1495891a20b1c5ae596af.jpg', '2023-02-23 20:57:27', 'admin', '2023-02-23 20:57:27', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628740820213469186, '2023/02/23/9383112a6f184478bc19d9c599d838ed.jpg', 't.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/9383112a6f184478bc19d9c599d838ed.jpg', '2023-02-23 20:57:27', 'admin', '2023-02-23 20:57:27', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628740820213469187, '2023/02/23/f64fce4f33d841c8a243b88dc1de9b38.jpeg', 'thelastofus,apocalyptic_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/02/23/f64fce4f33d841c8a243b88dc1de9b38.jpeg', '2023-02-23 20:57:27', 'admin', '2023-02-23 20:57:27', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628741384812924929, '2023/02/23/af9bed20744f4ebcacb08ee7e7fef96e.jpeg', 'Spider,Man,MaviC漫画,漫画,蜘蛛,超级英雄,标志,黑暗_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/02/23/af9bed20744f4ebcacb08ee7e7fef96e.jpeg', '2023-02-23 20:59:41', 'admin', '2023-02-23 20:59:41', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628741384812924930, '2023/02/23/a243f8d6f4624c77b0a5df4eaa5199b4.jpeg', 'scarlettjohansson,抽象,doubleexposure,undertheskin_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/02/23/a243f8d6f4624c77b0a5df4eaa5199b4.jpeg', '2023-02-23 20:59:41', 'admin', '2023-02-23 20:59:41', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628741384812924931, '2023/02/23/2eca7b1342d041f28d27caf5c33f8bee.jpg', 't.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/2eca7b1342d041f28d27caf5c33f8bee.jpg', '2023-02-23 20:59:41', 'admin', '2023-02-23 20:59:41', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742002663260161, '2023/02/23/db6e8324ed9e43639aa2d1e2ce1040d2.jpg', 'LOL新版皮肤稻草人联合王国,费德提克3440x1440壁纸_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/db6e8324ed9e43639aa2d1e2ce1040d2.jpg', '2023-02-23 21:02:09', 'admin', '2023-02-23 21:02:09', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742002663260162, '2023/02/23/cfbfb6e32b064237a0174ba5b4a7ac03.jpeg', 'LOL娜美3440x1440壁纸_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/02/23/cfbfb6e32b064237a0174ba5b4a7ac03.jpeg', '2023-02-23 21:02:09', 'admin', '2023-02-23 21:02:09', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742002663260163, '2023/02/23/9d7b2483cee54a709875938f87edafc7.jpg', 'Life,is,Strange,23440x1440带鱼屏壁纸_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/9d7b2483cee54a709875938f87edafc7.jpg', '2023-02-23 21:02:09', 'admin', '2023-02-23 21:02:09', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742501022162946, '2023/02/23/f0b43ffa8ef646c2bd53b2bc17b23096.jpg', 'windows10窗口4k高清壁纸图片_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/f0b43ffa8ef646c2bd53b2bc17b23096.jpg', '2023-02-23 21:04:07', 'admin', '2023-02-23 21:04:07', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742525693059074, '2023/02/23/8117dbbf17ac45038383c449346f1642.jpeg', 'thelastofus,apocalyptic_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/02/23/8117dbbf17ac45038383c449346f1642.jpeg', '2023-02-23 21:04:13', 'admin', '2023-02-23 21:04:13', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742525755973633, '2023/02/23/05a282c6e364474a802f29bcf42a48b1.jpg', 't.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/05a282c6e364474a802f29bcf42a48b1.jpg', '2023-02-23 21:04:13', 'admin', '2023-02-23 21:04:13', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1628742525885997058, '2023/02/23/c27113b003b84070bc4142cfbe81fe87.jpg', 'The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/23/c27113b003b84070bc4142cfbe81fe87.jpg', '2023-02-23 21:04:13', 'admin', '2023-02-23 21:04:13', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1630182637203202050, '2023/02/27/c1ed44bc66de4d648209d14b9d31bd69.jpg', 'The,Elder,Scrolls,Online_,Wolfhunter,上古卷轴3440x1440壁纸_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/27/c1ed44bc66de4d648209d14b9d31bd69.jpg', '2023-02-27 20:26:43', 'admin', '2023-02-27 20:26:43', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1630183789298819074, '2023/02/27/011af11410064e15bae1670d8b015fa2.jpg', 't.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/27/011af11410064e15bae1670d8b015fa2.jpg', '2023-02-27 20:31:17', 'admin', '2023-02-27 20:31:17', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1630392957024616450, '2023/02/28/37b8cdb431a3472e83252aa67896e497.jpg', '奥罗拉湖的夜晚,瑞士Bannalp湖,冰岛,极光,星空,4K壁纸_千叶网.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/02/28/37b8cdb431a3472e83252aa67896e497.jpg', '2023-02-28 10:22:27', 'admin', '2023-02-28 10:22:27', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1630396074092933122, '2023/02/28/8815c9b53d3f442bb096b7c400306ace.jpeg', 'thelastofus,apocalyptic_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/02/28/8815c9b53d3f442bb096b7c400306ace.jpeg', '2023-02-28 10:34:50', 'admin', '2023-02-28 10:34:50', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1633693827288043522, '2023/03/09/bf0032f388f249cd8d47b81ed24a26a4.jpeg', 'LOL娜美3440x1440壁纸_千叶网.jpeg', '.jpeg', 'http://127.0.0.1:9000/blog/2023/03/09/bf0032f388f249cd8d47b81ed24a26a4.jpeg', '2023-03-09 12:58:56', 'admin', '2023-03-09 12:58:56', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1634131376791998466, '2023/03/10/25c4de0f22244c16814e19f0818f8e29.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/10/25c4de0f22244c16814e19f0818f8e29.wav', '2023-03-10 17:57:36', NULL, '2023-03-10 17:57:36', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634132044038565890, '2023/03/10/80220840d3ad4464b985a570af567bcc.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/10/80220840d3ad4464b985a570af567bcc.wav', '2023-03-10 18:00:15', NULL, '2023-03-10 18:00:15', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634132647716364289, '2023/03/10/87e3915623a44d4cbdd9a6500c96bddb.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/10/87e3915623a44d4cbdd9a6500c96bddb.wav', '2023-03-10 18:02:39', NULL, '2023-03-10 18:02:39', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634132728049868801, '2023/03/10/770cb001c77640019d594a9373910792.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/10/770cb001c77640019d594a9373910792.wav', '2023-03-10 18:02:58', NULL, '2023-03-10 18:02:58', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634132983592034306, '2023/03/10/a8f56f0433c9416ba42322d38a9e8d64.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/10/a8f56f0433c9416ba42322d38a9e8d64.wav', '2023-03-10 18:03:59', NULL, '2023-03-10 18:03:59', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634483410246377473, '2023/03/11/8dbac03922f24a07bce8f0c28e540e47.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/11/8dbac03922f24a07bce8f0c28e540e47.wav', '2023-03-11 17:16:27', NULL, '2023-03-11 17:16:27', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634483538533359617, '2023/03/11/5310f49688eb4434bd40ce031b471230.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/11/5310f49688eb4434bd40ce031b471230.wav', '2023-03-11 17:16:57', NULL, '2023-03-11 17:16:57', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634483915358019585, '2023/03/11/59e254468a49495b8186a57bb5c60733.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/11/59e254468a49495b8186a57bb5c60733.wav', '2023-03-11 17:18:27', NULL, '2023-03-11 17:18:27', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1634487757118185473, '2023/03/11/ad5d9e1848b6497cb2d50e100103908a.wav', 'voice.wav', '.wav', 'http://127.0.0.1:9000/blog/2023/03/11/ad5d9e1848b6497cb2d50e100103908a.wav', '2023-03-11 17:33:43', NULL, '2023-03-11 17:33:43', NULL, 'minio'); +INSERT INTO `sys_oss` VALUES (1647487717082169345, '2023/04/16/dfddc05f9a9d48439599d442f2350646.jpg', '1164338.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/04/16/dfddc05f9a9d48439599d442f2350646.jpg', '2023-04-16 14:30:55', 'admin', '2023-04-16 14:30:55', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1647487957390622721, '2023/04/16/816497bf0865489a9563f4acdafa736b.jpg', 'QQ图片20210423133304.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/04/16/816497bf0865489a9563f4acdafa736b.jpg', '2023-04-16 14:31:53', 'admin', '2023-04-16 14:31:53', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1647910881729728513, '2023/04/17/fb6fdcfdf0b1426183c791fa20be4d24.jpg', 'QQ图片20210630102619.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/04/17/fb6fdcfdf0b1426183c791fa20be4d24.jpg', '2023-04-17 18:32:26', 'admin', '2023-04-17 18:32:26', 'admin', 'minio'); +INSERT INTO `sys_oss` VALUES (1647911339319906305, '2023/04/17/c45820d458654545b92c79c6fd148311.jpg', '1161451.jpg', '.jpg', 'http://127.0.0.1:9000/blog/2023/04/17/c45820d458654545b92c79c6fd148311.jpg', '2023-04-17 18:34:15', 'admin', '2023-04-17 18:34:15', 'admin', 'minio'); + +-- ---------------------------- +-- Table structure for sys_oss_config +-- ---------------------------- +DROP TABLE IF EXISTS `sys_oss_config`; +CREATE TABLE `sys_oss_config` ( + `oss_config_id` bigint(20) NOT NULL COMMENT '主建', + `config_key` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '配置key', + `access_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT 'accessKey', + `secret_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '秘钥', + `bucket_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '桶名称', + `prefix` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '前缀', + `endpoint` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '访问站点', + `domain` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '自定义域名', + `is_https` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'N' COMMENT '是否https(Y=是,N=否)', + `region` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '域', + `access_policy` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '1' COMMENT '桶权限类型(0=private 1=public 2=custom)', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '状态(0=正常,1=停用)', + `ext1` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '扩展字段', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`oss_config_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '对象存储配置表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_oss_config +-- ---------------------------- +INSERT INTO `sys_oss_config` VALUES (1, 'minio', '05BFXRnPh5nmBEjH', 'dZMNeKRRLZ7TheyHhvepfusURer9AWIt', 'blog', '', '127.0.0.1:9000', '', 'N', '', '1', '0', '', 'admin', '2023-01-05 19:54:19', 'admin', '2023-04-16 14:30:34', ''); +INSERT INTO `sys_oss_config` VALUES (2, 'qiniu', 'xxxxx', 'xxxxx', '420-image', '', 's3-cn-north-1.qiniucs.com', '', 'N', '', '1', '1', '', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-10 20:10:17', ''); +INSERT INTO `sys_oss_config` VALUES (3, 'aliyun', 'xxxx', 'xxxxx', '2831826106', '', 'oss-cn-beijing.aliyuncs.com', '', 'N', '', '1', '1', '', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-10 20:23:48', ''); +INSERT INTO `sys_oss_config` VALUES (4, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1250000000', '', 'cos.ap-beijing.myqcloud.com', '', 'N', 'ap-beijing', '1', '1', '', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-08 16:48:30', NULL); +INSERT INTO `sys_oss_config` VALUES (5, 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '', 'N', '', '1', '1', '', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-05 19:54:19', NULL); + +-- ---------------------------- +-- Table structure for sys_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_post`; +CREATE TABLE `sys_post` ( + `post_id` bigint(20) NOT NULL COMMENT '岗位ID', + `post_code` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '岗位编码', + `post_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '岗位名称', + `post_sort` int(4) NOT NULL COMMENT '显示顺序', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '状态(0正常 1停用)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`post_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '岗位信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_post +-- ---------------------------- +INSERT INTO `sys_post` VALUES (1, 'ceo', '董事长', 1, '0', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_post` VALUES (2, 'se', '项目经理', 2, '0', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_post` VALUES (3, 'hr', '人力资源', 3, '0', 'admin', '2023-01-05 19:54:19', '', NULL, ''); +INSERT INTO `sys_post` VALUES (4, 'user', '普通员工', 4, '0', 'admin', '2023-01-05 19:54:19', '', NULL, ''); + +-- ---------------------------- +-- Table structure for sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role`; +CREATE TABLE `sys_role` ( + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + `role_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称', + `role_key` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色权限字符串', + `role_sort` int(4) NOT NULL COMMENT '显示顺序', + `data_scope` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + `menu_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '菜单树选择项是否关联显示', + `dept_check_strictly` tinyint(1) NULL DEFAULT 1 COMMENT '部门树选择项是否关联显示', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`role_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role +-- ---------------------------- +INSERT INTO `sys_role` VALUES (1, '超级管理员', 'admin', 1, '1', 1, 1, '0', '0', 'admin', '2023-01-05 19:54:19', '', NULL, '超级管理员'); +INSERT INTO `sys_role` VALUES (2, '普通角色', 'common', 2, '2', 1, 1, '0', '0', 'admin', '2023-01-05 19:54:19', 'admin', '2023-02-25 21:17:19', '普通角色'); +INSERT INTO `sys_role` VALUES (3, '本部门及以下', 'test1', 3, '4', 1, 1, '0', '0', 'admin', '2023-01-05 19:54:34', 'admin', '2023-02-23 14:54:55', NULL); +INSERT INTO `sys_role` VALUES (4, '仅本人', 'test2', 4, '5', 1, 1, '0', '0', 'admin', '2023-01-05 19:54:34', 'admin', '2023-02-23 14:55:01', NULL); + +-- ---------------------------- +-- Table structure for sys_role_dept +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_dept`; +CREATE TABLE `sys_role_dept` ( + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + `dept_id` bigint(20) NOT NULL COMMENT '部门ID', + PRIMARY KEY (`role_id`, `dept_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色和部门关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_dept +-- ---------------------------- +INSERT INTO `sys_role_dept` VALUES (2, 100); +INSERT INTO `sys_role_dept` VALUES (2, 101); +INSERT INTO `sys_role_dept` VALUES (2, 105); + +-- ---------------------------- +-- Table structure for sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `sys_role_menu`; +CREATE TABLE `sys_role_menu` ( + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + `menu_id` bigint(20) NOT NULL COMMENT '菜单ID', + PRIMARY KEY (`role_id`, `menu_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色和菜单关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_role_menu +-- ---------------------------- +INSERT INTO `sys_role_menu` VALUES (2, 2); +INSERT INTO `sys_role_menu` VALUES (2, 3); +INSERT INTO `sys_role_menu` VALUES (2, 109); +INSERT INTO `sys_role_menu` VALUES (2, 112); +INSERT INTO `sys_role_menu` VALUES (2, 113); +INSERT INTO `sys_role_menu` VALUES (2, 114); +INSERT INTO `sys_role_menu` VALUES (2, 115); +INSERT INTO `sys_role_menu` VALUES (2, 1046); +INSERT INTO `sys_role_menu` VALUES (2, 1047); +INSERT INTO `sys_role_menu` VALUES (2, 1048); +INSERT INTO `sys_role_menu` VALUES (2, 1055); +INSERT INTO `sys_role_menu` VALUES (2, 1056); +INSERT INTO `sys_role_menu` VALUES (2, 1057); +INSERT INTO `sys_role_menu` VALUES (2, 1058); +INSERT INTO `sys_role_menu` VALUES (2, 1059); +INSERT INTO `sys_role_menu` VALUES (2, 1060); +INSERT INTO `sys_role_menu` VALUES (3, 1); +INSERT INTO `sys_role_menu` VALUES (3, 5); +INSERT INTO `sys_role_menu` VALUES (3, 100); +INSERT INTO `sys_role_menu` VALUES (3, 101); +INSERT INTO `sys_role_menu` VALUES (3, 102); +INSERT INTO `sys_role_menu` VALUES (3, 103); +INSERT INTO `sys_role_menu` VALUES (3, 104); +INSERT INTO `sys_role_menu` VALUES (3, 105); +INSERT INTO `sys_role_menu` VALUES (3, 106); +INSERT INTO `sys_role_menu` VALUES (3, 107); +INSERT INTO `sys_role_menu` VALUES (3, 108); +INSERT INTO `sys_role_menu` VALUES (3, 500); +INSERT INTO `sys_role_menu` VALUES (3, 501); +INSERT INTO `sys_role_menu` VALUES (3, 1001); +INSERT INTO `sys_role_menu` VALUES (3, 1002); +INSERT INTO `sys_role_menu` VALUES (3, 1003); +INSERT INTO `sys_role_menu` VALUES (3, 1004); +INSERT INTO `sys_role_menu` VALUES (3, 1005); +INSERT INTO `sys_role_menu` VALUES (3, 1006); +INSERT INTO `sys_role_menu` VALUES (3, 1007); +INSERT INTO `sys_role_menu` VALUES (3, 1008); +INSERT INTO `sys_role_menu` VALUES (3, 1009); +INSERT INTO `sys_role_menu` VALUES (3, 1010); +INSERT INTO `sys_role_menu` VALUES (3, 1011); +INSERT INTO `sys_role_menu` VALUES (3, 1012); +INSERT INTO `sys_role_menu` VALUES (3, 1013); +INSERT INTO `sys_role_menu` VALUES (3, 1014); +INSERT INTO `sys_role_menu` VALUES (3, 1015); +INSERT INTO `sys_role_menu` VALUES (3, 1016); +INSERT INTO `sys_role_menu` VALUES (3, 1017); +INSERT INTO `sys_role_menu` VALUES (3, 1018); +INSERT INTO `sys_role_menu` VALUES (3, 1019); +INSERT INTO `sys_role_menu` VALUES (3, 1020); +INSERT INTO `sys_role_menu` VALUES (3, 1021); +INSERT INTO `sys_role_menu` VALUES (3, 1022); +INSERT INTO `sys_role_menu` VALUES (3, 1023); +INSERT INTO `sys_role_menu` VALUES (3, 1024); +INSERT INTO `sys_role_menu` VALUES (3, 1025); +INSERT INTO `sys_role_menu` VALUES (3, 1026); +INSERT INTO `sys_role_menu` VALUES (3, 1027); +INSERT INTO `sys_role_menu` VALUES (3, 1028); +INSERT INTO `sys_role_menu` VALUES (3, 1029); +INSERT INTO `sys_role_menu` VALUES (3, 1030); +INSERT INTO `sys_role_menu` VALUES (3, 1031); +INSERT INTO `sys_role_menu` VALUES (3, 1032); +INSERT INTO `sys_role_menu` VALUES (3, 1033); +INSERT INTO `sys_role_menu` VALUES (3, 1034); +INSERT INTO `sys_role_menu` VALUES (3, 1035); +INSERT INTO `sys_role_menu` VALUES (3, 1036); +INSERT INTO `sys_role_menu` VALUES (3, 1037); +INSERT INTO `sys_role_menu` VALUES (3, 1038); +INSERT INTO `sys_role_menu` VALUES (3, 1039); +INSERT INTO `sys_role_menu` VALUES (3, 1040); +INSERT INTO `sys_role_menu` VALUES (3, 1041); +INSERT INTO `sys_role_menu` VALUES (3, 1042); +INSERT INTO `sys_role_menu` VALUES (3, 1043); +INSERT INTO `sys_role_menu` VALUES (3, 1044); +INSERT INTO `sys_role_menu` VALUES (3, 1045); +INSERT INTO `sys_role_menu` VALUES (3, 1500); +INSERT INTO `sys_role_menu` VALUES (3, 1501); +INSERT INTO `sys_role_menu` VALUES (3, 1502); +INSERT INTO `sys_role_menu` VALUES (3, 1503); +INSERT INTO `sys_role_menu` VALUES (3, 1504); +INSERT INTO `sys_role_menu` VALUES (3, 1505); +INSERT INTO `sys_role_menu` VALUES (3, 1506); +INSERT INTO `sys_role_menu` VALUES (3, 1507); +INSERT INTO `sys_role_menu` VALUES (3, 1508); +INSERT INTO `sys_role_menu` VALUES (3, 1509); +INSERT INTO `sys_role_menu` VALUES (3, 1510); +INSERT INTO `sys_role_menu` VALUES (3, 1511); +INSERT INTO `sys_role_menu` VALUES (3, 1610972802922405889); +INSERT INTO `sys_role_menu` VALUES (3, 1610973263779946497); +INSERT INTO `sys_role_menu` VALUES (3, 1611336461808898048); +INSERT INTO `sys_role_menu` VALUES (3, 1611336461808898049); +INSERT INTO `sys_role_menu` VALUES (3, 1611336461808898050); +INSERT INTO `sys_role_menu` VALUES (3, 1611336461808898051); +INSERT INTO `sys_role_menu` VALUES (3, 1611336461808898052); +INSERT INTO `sys_role_menu` VALUES (3, 1611336461808898053); +INSERT INTO `sys_role_menu` VALUES (3, 1611613727679938560); +INSERT INTO `sys_role_menu` VALUES (3, 1611613727679938561); +INSERT INTO `sys_role_menu` VALUES (3, 1611613727679938562); +INSERT INTO `sys_role_menu` VALUES (3, 1611613727679938563); +INSERT INTO `sys_role_menu` VALUES (3, 1611613727679938564); +INSERT INTO `sys_role_menu` VALUES (3, 1611613727679938565); +INSERT INTO `sys_role_menu` VALUES (3, 1611975928588574720); +INSERT INTO `sys_role_menu` VALUES (3, 1611975928588574721); +INSERT INTO `sys_role_menu` VALUES (3, 1611975928588574722); +INSERT INTO `sys_role_menu` VALUES (3, 1611975928588574723); +INSERT INTO `sys_role_menu` VALUES (3, 1611975928588574724); +INSERT INTO `sys_role_menu` VALUES (3, 1611975928588574725); +INSERT INTO `sys_role_menu` VALUES (4, 1); +INSERT INTO `sys_role_menu` VALUES (4, 5); +INSERT INTO `sys_role_menu` VALUES (4, 100); +INSERT INTO `sys_role_menu` VALUES (4, 101); +INSERT INTO `sys_role_menu` VALUES (4, 102); +INSERT INTO `sys_role_menu` VALUES (4, 103); +INSERT INTO `sys_role_menu` VALUES (4, 104); +INSERT INTO `sys_role_menu` VALUES (4, 105); +INSERT INTO `sys_role_menu` VALUES (4, 106); +INSERT INTO `sys_role_menu` VALUES (4, 107); +INSERT INTO `sys_role_menu` VALUES (4, 108); +INSERT INTO `sys_role_menu` VALUES (4, 118); +INSERT INTO `sys_role_menu` VALUES (4, 500); +INSERT INTO `sys_role_menu` VALUES (4, 501); +INSERT INTO `sys_role_menu` VALUES (4, 1001); +INSERT INTO `sys_role_menu` VALUES (4, 1002); +INSERT INTO `sys_role_menu` VALUES (4, 1003); +INSERT INTO `sys_role_menu` VALUES (4, 1004); +INSERT INTO `sys_role_menu` VALUES (4, 1005); +INSERT INTO `sys_role_menu` VALUES (4, 1006); +INSERT INTO `sys_role_menu` VALUES (4, 1007); +INSERT INTO `sys_role_menu` VALUES (4, 1008); +INSERT INTO `sys_role_menu` VALUES (4, 1009); +INSERT INTO `sys_role_menu` VALUES (4, 1010); +INSERT INTO `sys_role_menu` VALUES (4, 1011); +INSERT INTO `sys_role_menu` VALUES (4, 1012); +INSERT INTO `sys_role_menu` VALUES (4, 1013); +INSERT INTO `sys_role_menu` VALUES (4, 1014); +INSERT INTO `sys_role_menu` VALUES (4, 1015); +INSERT INTO `sys_role_menu` VALUES (4, 1016); +INSERT INTO `sys_role_menu` VALUES (4, 1017); +INSERT INTO `sys_role_menu` VALUES (4, 1018); +INSERT INTO `sys_role_menu` VALUES (4, 1019); +INSERT INTO `sys_role_menu` VALUES (4, 1020); +INSERT INTO `sys_role_menu` VALUES (4, 1021); +INSERT INTO `sys_role_menu` VALUES (4, 1022); +INSERT INTO `sys_role_menu` VALUES (4, 1023); +INSERT INTO `sys_role_menu` VALUES (4, 1024); +INSERT INTO `sys_role_menu` VALUES (4, 1025); +INSERT INTO `sys_role_menu` VALUES (4, 1026); +INSERT INTO `sys_role_menu` VALUES (4, 1027); +INSERT INTO `sys_role_menu` VALUES (4, 1028); +INSERT INTO `sys_role_menu` VALUES (4, 1029); +INSERT INTO `sys_role_menu` VALUES (4, 1030); +INSERT INTO `sys_role_menu` VALUES (4, 1031); +INSERT INTO `sys_role_menu` VALUES (4, 1032); +INSERT INTO `sys_role_menu` VALUES (4, 1033); +INSERT INTO `sys_role_menu` VALUES (4, 1034); +INSERT INTO `sys_role_menu` VALUES (4, 1035); +INSERT INTO `sys_role_menu` VALUES (4, 1036); +INSERT INTO `sys_role_menu` VALUES (4, 1037); +INSERT INTO `sys_role_menu` VALUES (4, 1038); +INSERT INTO `sys_role_menu` VALUES (4, 1039); +INSERT INTO `sys_role_menu` VALUES (4, 1040); +INSERT INTO `sys_role_menu` VALUES (4, 1041); +INSERT INTO `sys_role_menu` VALUES (4, 1042); +INSERT INTO `sys_role_menu` VALUES (4, 1043); +INSERT INTO `sys_role_menu` VALUES (4, 1044); +INSERT INTO `sys_role_menu` VALUES (4, 1045); +INSERT INTO `sys_role_menu` VALUES (4, 1050); +INSERT INTO `sys_role_menu` VALUES (4, 1500); +INSERT INTO `sys_role_menu` VALUES (4, 1501); +INSERT INTO `sys_role_menu` VALUES (4, 1502); +INSERT INTO `sys_role_menu` VALUES (4, 1503); +INSERT INTO `sys_role_menu` VALUES (4, 1504); +INSERT INTO `sys_role_menu` VALUES (4, 1505); +INSERT INTO `sys_role_menu` VALUES (4, 1506); +INSERT INTO `sys_role_menu` VALUES (4, 1507); +INSERT INTO `sys_role_menu` VALUES (4, 1508); +INSERT INTO `sys_role_menu` VALUES (4, 1509); +INSERT INTO `sys_role_menu` VALUES (4, 1510); +INSERT INTO `sys_role_menu` VALUES (4, 1511); +INSERT INTO `sys_role_menu` VALUES (4, 1600); +INSERT INTO `sys_role_menu` VALUES (4, 1601); +INSERT INTO `sys_role_menu` VALUES (4, 1602); +INSERT INTO `sys_role_menu` VALUES (4, 1603); +INSERT INTO `sys_role_menu` VALUES (4, 1604); +INSERT INTO `sys_role_menu` VALUES (4, 1605); +INSERT INTO `sys_role_menu` VALUES (4, 1610972802922405889); +INSERT INTO `sys_role_menu` VALUES (4, 1610973263779946497); +INSERT INTO `sys_role_menu` VALUES (4, 1611336461808898048); +INSERT INTO `sys_role_menu` VALUES (4, 1611336461808898049); +INSERT INTO `sys_role_menu` VALUES (4, 1611336461808898050); +INSERT INTO `sys_role_menu` VALUES (4, 1611336461808898051); +INSERT INTO `sys_role_menu` VALUES (4, 1611336461808898052); +INSERT INTO `sys_role_menu` VALUES (4, 1611336461808898053); +INSERT INTO `sys_role_menu` VALUES (4, 1611613727679938560); +INSERT INTO `sys_role_menu` VALUES (4, 1611613727679938561); +INSERT INTO `sys_role_menu` VALUES (4, 1611613727679938562); +INSERT INTO `sys_role_menu` VALUES (4, 1611613727679938563); +INSERT INTO `sys_role_menu` VALUES (4, 1611613727679938564); +INSERT INTO `sys_role_menu` VALUES (4, 1611613727679938565); +INSERT INTO `sys_role_menu` VALUES (4, 1611975928588574720); +INSERT INTO `sys_role_menu` VALUES (4, 1611975928588574721); +INSERT INTO `sys_role_menu` VALUES (4, 1611975928588574722); +INSERT INTO `sys_role_menu` VALUES (4, 1611975928588574723); +INSERT INTO `sys_role_menu` VALUES (4, 1611975928588574724); +INSERT INTO `sys_role_menu` VALUES (4, 1611975928588574725); + +-- ---------------------------- +-- Table structure for sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user`; +CREATE TABLE `sys_user` ( + `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID', + `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门ID', + `user_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户账号', + `nick_name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户昵称', + `user_type` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT 'sys_user' COMMENT '用户类型(sys_user系统用户)', + `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '用户邮箱', + `phonenumber` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '手机号码', + `sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)', + `avatar` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '头像地址', + `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '密码', + `status` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '帐号状态(0正常 1停用)', + `del_flag` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `login_ip` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '最后登录IP', + `login_date` datetime NULL DEFAULT NULL COMMENT '最后登录时间', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '创建者', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '更新者', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注', + `web_site` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '个人网站', + `intro` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '个人简介', + PRIMARY KEY (`user_id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1614548939325845512 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户信息表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user +-- ---------------------------- +INSERT INTO `sys_user` VALUES (1, 104, 'admin', 'water-之', 'sys_user', '2831826106@qq.com', '18888888888', '0', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/13/69a29185d99642fc926a62f86305b3fe.jpg', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2023-04-17 18:32:00', 'admin', '2023-01-05 19:54:19', 'admin', '2023-04-17 18:32:00', '管理员', NULL, NULL); +INSERT INTO `sys_user` VALUES (2, 104, 'lionli', '疯狂的狮子Li', 'sys_user', 'crazyLionLi@qq.com', '15666666666', '1', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2023-01-05 19:54:19', 'admin', '2023-01-05 19:54:19', 'admin', '2023-01-15 14:26:04', '测试员', NULL, NULL); +INSERT INTO `sys_user` VALUES (3, 104, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', '2023-04-17 18:16:52', 'admin', '2023-01-05 19:54:34', 'test', '2023-04-17 18:16:52', NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (4, 104, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', 'http://2831826106.oss-cn-beijing.aliyuncs.com/2023/01/10/180d5a6553f04ebda0c70efd8c69bebe.jpg', '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', '2023-03-09 19:30:25', 'admin', '2023-01-05 19:54:34', 'test1', '2023-03-09 19:30:25', NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (5, NULL, '荷塘', '荷塘', 'sys_user', '2831826106@qq.com', '', '0', 'https://s1.ax1x.com/2023/01/15/pSQf91A.jpg', '$2a$10$h0IknNHCPWIe9o1NuThugOI2mhCqcXyrJd5a86/XOEO4ClTGVbwZW', '0', '0', '127.0.0.1', '2023-01-19 23:00:18', '老妈', '2023-01-15 17:01:45', '荷塘', '2023-01-19 23:00:18', NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (6, NULL, '月色', '月色', 'sys_user', '2831826106@qq.com', '', '0', 'https://s1.ax1x.com/2023/01/15/pSQf91A.jpg', '$2a$10$4XkCMVnhmntbicUiy.cx6.BWrzWGGsEvqqgCLl.UqUP6g92YpZj3e', '0', '0', '127.0.0.1', '2023-01-19 22:23:11', '老爸', '2023-01-15 17:03:59', '月色', '2023-01-19 22:23:11', NULL, NULL, '热爱学习'); +INSERT INTO `sys_user` VALUES (7, NULL, '测试', '测试', 'sys_user', '2831826106@qq.com', '', '0', 'https://s1.ax1x.com/2023/01/15/pSQf91A.jpg', '$2a$10$oVCi4XG.DByyZa77YJkRUuoc7CwEV7U0LSqnNqAhMJT2Z3CHFchIy', '0', '0', '127.0.0.1', '2023-01-17 13:40:32', '测试', '2023-01-17 13:40:31', '测试', '2023-01-17 13:40:32', NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (1614548939325845508, NULL, 'lasttest', 'lasttest', 'sys_user', '2831826106@qq.com', '', '0', 'https://s1.ax1x.com/2023/01/15/pSQf91A.jpg', '$2a$10$druteqFvNhYp5rJLfOjzw.X5lmIIar2LyhielGFi.2mAPGlydidUe', '0', '0', '127.0.0.1', '2023-01-17 13:47:16', 'lasttest', '2023-01-17 13:47:16', 'lasttest', '2023-01-17 13:47:16', NULL, NULL, NULL); +INSERT INTO `sys_user` VALUES (1614548939325845510, NULL, 'kalashok-pan', '卡拉肖克-潘', 'sys_user', '', '', '0', 'https://foruda.gitee.com/avatar/1673853732714613266/8669563_kalashok-pan_1673853732.png', '$2a$10$02fRUrt.2aF5mjfYLLryjOtUEt4yQR3v3hF52eo8/.t7.ZliDTGjW', '0', '0', '127.0.0.1', '2023-01-21 22:14:36', 'kalashok-pan', '2023-01-21 14:10:29', 'admin', '2023-02-11 13:10:27', '暂无', NULL, NULL); +INSERT INTO `sys_user` VALUES (1614548939325845511, NULL, '测试666', '测试666', 'sys_user', '2831826106@qq.com', '', '0', 'https://s1.ax1x.com/2023/01/15/pSQf91A.jpg', '$2a$10$PejLOGmhG2gRlr6UJdpriuijHixN9mDqYpVQ6LCin5tKOYpL5LiYi', '0', '0', '127.0.0.1', '2023-02-12 12:30:03', '测试666', '2023-02-12 12:30:03', '测试666', '2023-02-12 12:30:03', NULL, NULL, NULL); + +-- ---------------------------- +-- Table structure for sys_user_post +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_post`; +CREATE TABLE `sys_user_post` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `post_id` bigint(20) NOT NULL COMMENT '岗位ID', + PRIMARY KEY (`user_id`, `post_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户与岗位关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_post +-- ---------------------------- +INSERT INTO `sys_user_post` VALUES (1, 1); +INSERT INTO `sys_user_post` VALUES (2, 2); + +-- ---------------------------- +-- Table structure for sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `sys_user_role`; +CREATE TABLE `sys_user_role` ( + `user_id` bigint(20) NOT NULL COMMENT '用户ID', + `role_id` bigint(20) NOT NULL COMMENT '角色ID', + PRIMARY KEY (`user_id`, `role_id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户和角色关联表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of sys_user_role +-- ---------------------------- +INSERT INTO `sys_user_role` VALUES (1, 1); +INSERT INTO `sys_user_role` VALUES (2, 2); +INSERT INTO `sys_user_role` VALUES (3, 3); +INSERT INTO `sys_user_role` VALUES (4, 2); +INSERT INTO `sys_user_role` VALUES (1614548939325845510, 4); + +-- ---------------------------- +-- Table structure for test_demo +-- ---------------------------- +DROP TABLE IF EXISTS `test_demo`; +CREATE TABLE `test_demo` ( + `id` bigint(20) NOT NULL COMMENT '主键', + `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门id', + `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id', + `order_num` int(11) NULL DEFAULT 0 COMMENT '排序号', + `test_key` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'key键', + `value` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '值', + `version` int(11) NULL DEFAULT 0 COMMENT '版本', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `del_flag` int(11) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '测试单表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of test_demo +-- ---------------------------- +INSERT INTO `test_demo` VALUES (1, 102, 4, 1, '测试数据权限', '测试', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (2, 102, 3, 2, '子节点1', '111', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (3, 102, 3, 3, '子节点2', '222', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (4, 108, 4, 4, '测试数据', 'demo', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (5, 108, 3, 13, '子节点11', '1111', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (6, 108, 3, 12, '子节点22', '2222', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (7, 108, 3, 11, '子节点33', '3333', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (8, 108, 3, 10, '子节点44', '4444', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (9, 108, 3, 9, '子节点55', '5555', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (10, 108, 3, 8, '子节点66', '6666', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (11, 108, 3, 7, '子节点77', '7777', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (12, 108, 3, 6, '子节点88', '8888', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_demo` VALUES (13, 108, 3, 5, '子节点99', '9999', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for test_tree +-- ---------------------------- +DROP TABLE IF EXISTS `test_tree`; +CREATE TABLE `test_tree` ( + `id` bigint(20) NOT NULL COMMENT '主键', + `parent_id` bigint(20) NULL DEFAULT 0 COMMENT '父id', + `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '部门id', + `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id', + `tree_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '值', + `version` int(11) NULL DEFAULT 0 COMMENT '版本', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '更新人', + `del_flag` int(11) NULL DEFAULT 0 COMMENT '删除标志', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '测试树表' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of test_tree +-- ---------------------------- +INSERT INTO `test_tree` VALUES (1, 0, 102, 4, '测试数据权限', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (2, 1, 102, 3, '子节点1', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (3, 2, 102, 3, '子节点2', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (4, 0, 108, 4, '测试树1', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (5, 4, 108, 3, '子节点11', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (6, 4, 108, 3, '子节点22', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (7, 4, 108, 3, '子节点33', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (8, 5, 108, 3, '子节点44', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (9, 6, 108, 3, '子节点55', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (10, 7, 108, 3, '子节点66', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (11, 7, 108, 3, '子节点77', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (12, 10, 108, 3, '子节点88', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); +INSERT INTO `test_tree` VALUES (13, 10, 108, 3, '子节点99', 0, '2023-01-05 19:54:34', 'admin', NULL, NULL, 0); + +-- ---------------------------- +-- Table structure for user_article_operation +-- ---------------------------- +DROP TABLE IF EXISTS `user_article_operation`; +CREATE TABLE `user_article_operation` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` bigint(20) NULL DEFAULT NULL, + `article_id` int(11) NULL DEFAULT NULL, + `operation_type` int(11) NULL DEFAULT NULL COMMENT '点赞为1,收藏为2(计算分数时点赞3分,收藏5分)', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 55 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Records of user_article_operation +-- ---------------------------- +INSERT INTO `user_article_operation` VALUES (53, 1, 156, 1); +INSERT INTO `user_article_operation` VALUES (54, 1, 157, 1); + +-- ---------------------------- +-- Table structure for xxl_job_group +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_group`; +CREATE TABLE `xxl_job_group` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `app_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '执行器AppName', + `title` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '执行器名称', + `address_type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '执行器地址类型:0=自动注册、1=手动录入', + `address_list` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '执行器地址列表,多地址逗号分隔', + `update_time` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_group +-- ---------------------------- +INSERT INTO `xxl_job_group` VALUES (1, 'xxl-job-executor', '示例执行器', 0, NULL, '2023-02-23 16:41:23'); + +-- ---------------------------- +-- Table structure for xxl_job_info +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_info`; +CREATE TABLE `xxl_job_info` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` int(11) NOT NULL COMMENT '执行器主键ID', + `job_desc` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `add_time` datetime NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + `author` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '作者', + `alarm_email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '报警邮件', + `schedule_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'NONE' COMMENT '调度类型', + `schedule_conf` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '调度配置,值含义取决于调度类型', + `misfire_strategy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT 'DO_NOTHING' COMMENT '调度过期策略', + `executor_route_strategy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器路由策略', + `executor_handler` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器任务handler', + `executor_param` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器任务参数', + `executor_block_strategy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '阻塞处理策略', + `executor_timeout` int(11) NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒', + `executor_fail_retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '失败重试次数', + `glue_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'GLUE类型', + `glue_source` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'GLUE源代码', + `glue_remark` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'GLUE备注', + `glue_updatetime` datetime NULL DEFAULT NULL COMMENT 'GLUE更新时间', + `child_jobid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '子任务ID,多个逗号分隔', + `trigger_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '调度状态:0-停止,1-运行', + `trigger_last_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '上次调度时间', + `trigger_next_time` bigint(13) NOT NULL DEFAULT 0 COMMENT '下次调度时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_info +-- ---------------------------- +INSERT INTO `xxl_job_info` VALUES (1, 1, '测试任务1', '2018-11-03 22:21:31', '2018-11-03 22:21:31', 'XXL', '', 'CRON', '0 0 0 * * ? *', 'DO_NOTHING', 'FIRST', 'demoJobHandler', '', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2018-11-03 22:21:31', '', 0, 0, 0); + +-- ---------------------------- +-- Table structure for xxl_job_lock +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_lock`; +CREATE TABLE `xxl_job_lock` ( + `lock_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '锁名称', + PRIMARY KEY (`lock_name`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_lock +-- ---------------------------- +INSERT INTO `xxl_job_lock` VALUES ('schedule_lock'); + +-- ---------------------------- +-- Table structure for xxl_job_log +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_log`; +CREATE TABLE `xxl_job_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `job_group` int(11) NOT NULL COMMENT '执行器主键ID', + `job_id` int(11) NOT NULL COMMENT '任务,主键ID', + `executor_address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器地址,本次执行的地址', + `executor_handler` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器任务handler', + `executor_param` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器任务参数', + `executor_sharding_param` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2', + `executor_fail_retry_count` int(11) NOT NULL DEFAULT 0 COMMENT '失败重试次数', + `trigger_time` datetime NULL DEFAULT NULL COMMENT '调度-时间', + `trigger_code` int(11) NOT NULL COMMENT '调度-结果', + `trigger_msg` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '调度-日志', + `handle_time` datetime NULL DEFAULT NULL COMMENT '执行-时间', + `handle_code` int(11) NOT NULL COMMENT '执行-状态', + `handle_msg` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '执行-日志', + `alarm_status` tinyint(4) NOT NULL DEFAULT 0 COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败', + PRIMARY KEY (`id`) USING BTREE, + INDEX `I_trigger_time`(`trigger_time` ASC) USING BTREE, + INDEX `I_handle_code`(`handle_code` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_log +-- ---------------------------- + +-- ---------------------------- +-- Table structure for xxl_job_log_report +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_log_report`; +CREATE TABLE `xxl_job_log_report` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `trigger_day` datetime NULL DEFAULT NULL COMMENT '调度-时间', + `running_count` int(11) NOT NULL DEFAULT 0 COMMENT '运行中-日志数量', + `suc_count` int(11) NOT NULL DEFAULT 0 COMMENT '执行成功-日志数量', + `fail_count` int(11) NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量', + `update_time` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `i_trigger_day`(`trigger_day` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 41 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_log_report +-- ---------------------------- +INSERT INTO `xxl_job_log_report` VALUES (1, '2023-01-05 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (2, '2023-01-04 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (3, '2023-01-03 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (4, '2023-01-06 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (5, '2023-01-07 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (6, '2023-01-08 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (7, '2023-01-09 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (8, '2023-01-10 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (9, '2023-01-11 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (10, '2023-01-12 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (11, '2023-01-13 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (12, '2023-01-14 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (13, '2023-01-15 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (14, '2023-01-16 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (15, '2023-01-17 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (16, '2023-01-18 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (17, '2023-01-19 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (18, '2023-01-20 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (19, '2023-01-21 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (20, '2023-01-22 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (21, '2023-01-23 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (22, '2023-01-24 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (23, '2023-02-08 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (24, '2023-02-07 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (25, '2023-02-06 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (26, '2023-02-09 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (27, '2023-02-11 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (28, '2023-02-10 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (29, '2023-02-12 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (30, '2023-02-13 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (31, '2023-02-14 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (32, '2023-02-15 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (33, '2023-02-16 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (34, '2023-02-17 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (35, '2023-02-18 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (36, '2023-02-19 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (37, '2023-02-20 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (38, '2023-02-21 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (39, '2023-02-22 00:00:00', 0, 0, 0, NULL); +INSERT INTO `xxl_job_log_report` VALUES (40, '2023-02-23 00:00:00', 0, 0, 0, NULL); + +-- ---------------------------- +-- Table structure for xxl_job_logglue +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_logglue`; +CREATE TABLE `xxl_job_logglue` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_id` int(11) NOT NULL COMMENT '任务,主键ID', + `glue_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'GLUE类型', + `glue_source` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT 'GLUE源代码', + `glue_remark` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT 'GLUE备注', + `add_time` datetime NULL DEFAULT NULL, + `update_time` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_logglue +-- ---------------------------- + +-- ---------------------------- +-- Table structure for xxl_job_registry +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_registry`; +CREATE TABLE `xxl_job_registry` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `registry_group` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `registry_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `registry_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, + `update_time` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE, + INDEX `i_g_k_v`(`registry_group` ASC, `registry_key` ASC, `registry_value` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 327 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_registry +-- ---------------------------- + +-- ---------------------------- +-- Table structure for xxl_job_user +-- ---------------------------- +DROP TABLE IF EXISTS `xxl_job_user`; +CREATE TABLE `xxl_job_user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '账号', + `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码', + `role` tinyint(4) NOT NULL COMMENT '角色:0-普通用户、1-管理员', + `permission` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割', + PRIMARY KEY (`id`) USING BTREE, + UNIQUE INDEX `i_username`(`username` ASC) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Records of xxl_job_user +-- ---------------------------- +INSERT INTO `xxl_job_user` VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL); + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/script/sql/sql.md b/script/sql/sql.md new file mode 100644 index 0000000..02bd144 --- /dev/null +++ b/script/sql/sql.md @@ -0,0 +1 @@ +# 加入qq群:551275273 了解博客部署教程 \ No newline at end of file diff --git a/zhi-admin-ui/.editorconfig b/zhi-admin-ui/.editorconfig new file mode 100644 index 0000000..7034f9b --- /dev/null +++ b/zhi-admin-ui/.editorconfig @@ -0,0 +1,22 @@ +# 告诉EditorConfig插件,这是根文件,不用继续往上查找 +root = true + +# 匹配全部文件 +[*] +# 设置字符集 +charset = utf-8 +# 缩进风格,可选space、tab +indent_style = space +# 缩进的空格数 +indent_size = 2 +# 结尾换行符,可选lf、cr、crlf +end_of_line = lf +# 在文件结尾插入新行 +insert_final_newline = true +# 删除一行中的前后空格 +trim_trailing_whitespace = true + +# 匹配md结尾的文件 +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/zhi-admin-ui/.env.development b/zhi-admin-ui/.env.development new file mode 100644 index 0000000..bbd575e --- /dev/null +++ b/zhi-admin-ui/.env.development @@ -0,0 +1,18 @@ +# 页面标题 +VUE_APP_TITLE = zhi-water的博客 + +# 开发环境配置 +ENV = 'development' + +# 若依管理系统/开发环境 +VUE_APP_BASE_API = '/dev-api' + +# 应用访问路径 例如使用前缀 /admin/ +VUE_APP_CONTEXT_PATH = '/' + + +# xxl-job 控制台地址 +VUE_APP_XXL_JOB_ADMIN = 'http://localhost:9100/xxl-job-admin' + +# 路由懒加载 +VUE_CLI_BABEL_TRANSPILE_MODULES = true diff --git a/zhi-admin-ui/.env.production b/zhi-admin-ui/.env.production new file mode 100644 index 0000000..0ab440a --- /dev/null +++ b/zhi-admin-ui/.env.production @@ -0,0 +1,15 @@ +# 页面标题 +VUE_APP_TITLE = zhi-water的博客 + +# 生产环境配置 +ENV = 'production' + +# 应用访问路径 例如使用前缀 /admin/ +VUE_APP_CONTEXT_PATH = '/' + + +# 监控地址 +VUE_APP_XXL_JOB_ADMIN = '/xxl-job-admin' + +# 若依管理系统/生产环境 +VUE_APP_BASE_API = '/prod-api' diff --git a/zhi-admin-ui/.eslintignore b/zhi-admin-ui/.eslintignore new file mode 100644 index 0000000..89be6f6 --- /dev/null +++ b/zhi-admin-ui/.eslintignore @@ -0,0 +1,10 @@ +# 忽略build目录下类型为js的文件的语法检查 +build/*.js +# 忽略src/assets目录下文件的语法检查 +src/assets +# 忽略public目录下文件的语法检查 +public +# 忽略当前目录下为js的文件的语法检查 +*.js +# 忽略当前目录下为vue的文件的语法检查 +*.vue \ No newline at end of file diff --git a/zhi-admin-ui/.eslintrc.js b/zhi-admin-ui/.eslintrc.js new file mode 100644 index 0000000..82bbdee --- /dev/null +++ b/zhi-admin-ui/.eslintrc.js @@ -0,0 +1,199 @@ +// ESlint 检查配置 +module.exports = { + root: true, + parserOptions: { + parser: 'babel-eslint', + sourceType: 'module' + }, + env: { + browser: true, + node: true, + es6: true, + }, + extends: ['plugin:vue/recommended', 'eslint:recommended'], + + // add your custom rules here + //it is base on https://github.com/vuejs/eslint-config-vue + rules: { + "vue/max-attributes-per-line": [2, { + "singleline": 10, + "multiline": { + "max": 1, + "allowFirstLine": false + } + }], + "vue/singleline-html-element-content-newline": "off", + "vue/multiline-html-element-content-newline":"off", + "vue/name-property-casing": ["error", "PascalCase"], + "vue/no-v-html": "off", + 'accessor-pairs': 2, + 'arrow-spacing': [2, { + 'before': true, + 'after': true + }], + 'block-spacing': [2, 'always'], + 'brace-style': [2, '1tbs', { + 'allowSingleLine': true + }], + 'camelcase': [0, { + 'properties': 'always' + }], + 'comma-dangle': [2, 'never'], + 'comma-spacing': [2, { + 'before': false, + 'after': true + }], + 'comma-style': [2, 'last'], + 'constructor-super': 2, + 'curly': [2, 'multi-line'], + 'dot-location': [2, 'property'], + 'eol-last': 2, + 'eqeqeq': ["error", "always", {"null": "ignore"}], + 'generator-star-spacing': [2, { + 'before': true, + 'after': true + }], + 'handle-callback-err': [2, '^(err|error)$'], + 'indent': [2, 2, { + 'SwitchCase': 1 + }], + 'jsx-quotes': [2, 'prefer-single'], + 'key-spacing': [2, { + 'beforeColon': false, + 'afterColon': true + }], + 'keyword-spacing': [2, { + 'before': true, + 'after': true + }], + 'new-cap': [2, { + 'newIsCap': true, + 'capIsNew': false + }], + 'new-parens': 2, + 'no-array-constructor': 2, + 'no-caller': 2, + 'no-console': 'off', + 'no-class-assign': 2, + 'no-cond-assign': 2, + 'no-const-assign': 2, + 'no-control-regex': 0, + 'no-delete-var': 2, + 'no-dupe-args': 2, + 'no-dupe-class-members': 2, + 'no-dupe-keys': 2, + 'no-duplicate-case': 2, + 'no-empty-character-class': 2, + 'no-empty-pattern': 2, + 'no-eval': 2, + 'no-ex-assign': 2, + 'no-extend-native': 2, + 'no-extra-bind': 2, + 'no-extra-boolean-cast': 2, + 'no-extra-parens': [2, 'functions'], + 'no-fallthrough': 2, + 'no-floating-decimal': 2, + 'no-func-assign': 2, + 'no-implied-eval': 2, + 'no-inner-declarations': [2, 'functions'], + 'no-invalid-regexp': 2, + 'no-irregular-whitespace': 2, + 'no-iterator': 2, + 'no-label-var': 2, + 'no-labels': [2, { + 'allowLoop': false, + 'allowSwitch': false + }], + 'no-lone-blocks': 2, + 'no-mixed-spaces-and-tabs': 2, + 'no-multi-spaces': 2, + 'no-multi-str': 2, + 'no-multiple-empty-lines': [2, { + 'max': 1 + }], + 'no-native-reassign': 2, + 'no-negated-in-lhs': 2, + 'no-new-object': 2, + 'no-new-require': 2, + 'no-new-symbol': 2, + 'no-new-wrappers': 2, + 'no-obj-calls': 2, + 'no-octal': 2, + 'no-octal-escape': 2, + 'no-path-concat': 2, + 'no-proto': 2, + 'no-redeclare': 2, + 'no-regex-spaces': 2, + 'no-return-assign': [2, 'except-parens'], + 'no-self-assign': 2, + 'no-self-compare': 2, + 'no-sequences': 2, + 'no-shadow-restricted-names': 2, + 'no-spaced-func': 2, + 'no-sparse-arrays': 2, + 'no-this-before-super': 2, + 'no-throw-literal': 2, + 'no-trailing-spaces': 2, + 'no-undef': 2, + 'no-undef-init': 2, + 'no-unexpected-multiline': 2, + 'no-unmodified-loop-condition': 2, + 'no-unneeded-ternary': [2, { + 'defaultAssignment': false + }], + 'no-unreachable': 2, + 'no-unsafe-finally': 2, + 'no-unused-vars': [2, { + 'vars': 'all', + 'args': 'none' + }], + 'no-useless-call': 2, + 'no-useless-computed-key': 2, + 'no-useless-constructor': 2, + 'no-useless-escape': 0, + 'no-whitespace-before-property': 2, + 'no-with': 2, + 'one-var': [2, { + 'initialized': 'never' + }], + 'operator-linebreak': [2, 'after', { + 'overrides': { + '?': 'before', + ':': 'before' + } + }], + 'padded-blocks': [2, 'never'], + 'quotes': [2, 'single', { + 'avoidEscape': true, + 'allowTemplateLiterals': true + }], + 'semi': [2, 'never'], + 'semi-spacing': [2, { + 'before': false, + 'after': true + }], + 'space-before-blocks': [2, 'always'], + 'space-before-function-paren': [2, 'never'], + 'space-in-parens': [2, 'never'], + 'space-infix-ops': 2, + 'space-unary-ops': [2, { + 'words': true, + 'nonwords': false + }], + 'spaced-comment': [2, 'always', { + 'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] + }], + 'template-curly-spacing': [2, 'never'], + 'use-isnan': 2, + 'valid-typeof': 2, + 'wrap-iife': [2, 'any'], + 'yield-star-spacing': [2, 'both'], + 'yoda': [2, 'never'], + 'prefer-const': 2, + 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, + 'object-curly-spacing': [2, 'always', { + objectsInObjects: false + }], + 'array-bracket-spacing': [2, 'never'] + } +} diff --git a/zhi-admin-ui/.gitignore b/zhi-admin-ui/.gitignore new file mode 100644 index 0000000..78a752d --- /dev/null +++ b/zhi-admin-ui/.gitignore @@ -0,0 +1,23 @@ +.DS_Store +node_modules/ +dist/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +**/*.log + +tests/**/coverage/ +tests/e2e/reports +selenium-debug.log + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.local + +package-lock.json +yarn.lock diff --git a/zhi-admin-ui/README.md b/zhi-admin-ui/README.md new file mode 100644 index 0000000..00c0ab8 --- /dev/null +++ b/zhi-admin-ui/README.md @@ -0,0 +1,30 @@ +## 开发 + +```bash +# 克隆项目 +git clone https://gitee.com/y_project/RuoYi-Vue + +# 进入项目目录 +cd ruoyi-ui + +# 安装依赖 +npm install + +# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 +npm install --registry=https://registry.npmmirror.com + +# 启动服务 +npm run dev +``` + +浏览器访问 http://localhost:80 + +## 发布 + +```bash +# 构建测试环境 +npm run build:stage + +# 构建生产环境 +npm run build:prod +``` \ No newline at end of file diff --git a/zhi-admin-ui/babel.config.js b/zhi-admin-ui/babel.config.js new file mode 100644 index 0000000..b99f001 --- /dev/null +++ b/zhi-admin-ui/babel.config.js @@ -0,0 +1,13 @@ +module.exports = { + presets: [ + // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app + '@vue/cli-plugin-babel/preset' + ], + 'env': { + 'development': { + // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require(). + // This plugin can significantly increase the speed of hot updates, when you have a large number of pages. + 'plugins': ['dynamic-import-node'] + } + } +} diff --git a/zhi-admin-ui/bin/build.bat b/zhi-admin-ui/bin/build.bat new file mode 100644 index 0000000..dda590d --- /dev/null +++ b/zhi-admin-ui/bin/build.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [Ϣ] Weḅdistļ +echo. + +%~d0 +cd %~dp0 + +cd .. +npm run build:prod + +pause \ No newline at end of file diff --git a/zhi-admin-ui/bin/package.bat b/zhi-admin-ui/bin/package.bat new file mode 100644 index 0000000..2f22a4a --- /dev/null +++ b/zhi-admin-ui/bin/package.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [信息] 安装Web工程,生成node_modules文件。 +echo. + +%~d0 +cd %~dp0 + +cd .. +npm install --registry=https://registry.npmmirror.com + +pause diff --git a/zhi-admin-ui/bin/run-web.bat b/zhi-admin-ui/bin/run-web.bat new file mode 100644 index 0000000..0318c52 --- /dev/null +++ b/zhi-admin-ui/bin/run-web.bat @@ -0,0 +1,12 @@ +@echo off +echo. +echo [信息] 使用 Vue CLI 命令运行 Web 工程。 +echo. + +%~d0 +cd %~dp0 + +cd .. +npm run dev + +pause \ No newline at end of file diff --git a/zhi-admin-ui/build/index.js b/zhi-admin-ui/build/index.js new file mode 100644 index 0000000..0c57de2 --- /dev/null +++ b/zhi-admin-ui/build/index.js @@ -0,0 +1,35 @@ +const { run } = require('runjs') +const chalk = require('chalk') +const config = require('../vue.config.js') +const rawArgv = process.argv.slice(2) +const args = rawArgv.join(' ') + +if (process.env.npm_config_preview || rawArgv.includes('--preview')) { + const report = rawArgv.includes('--report') + + run(`vue-cli-service build ${args}`) + + const port = 9526 + const publicPath = config.publicPath + + var connect = require('connect') + var serveStatic = require('serve-static') + const app = connect() + + app.use( + publicPath, + serveStatic('./dist', { + index: ['index.html', '/'] + }) + ) + + app.listen(port, function () { + console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) + if (report) { + console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) + } + + }) +} else { + run(`vue-cli-service build ${args}`) +} diff --git a/zhi-admin-ui/package.json b/zhi-admin-ui/package.json new file mode 100644 index 0000000..5637cb5 --- /dev/null +++ b/zhi-admin-ui/package.json @@ -0,0 +1,96 @@ +{ + "name": "ruoyi-vue-plus", + "version": "4.4.0", + "description": "RuoYi-Vue-Plus后台管理系统", + "author": "LionLi", + "license": "MIT", + "scripts": { + "dev": "vue-cli-service serve", + "build:prod": "vue-cli-service build", + "preview": "node build/index.js --preview", + "lint": "eslint --ext .js,.vue src" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "src/**/*.{js,vue}": [ + "eslint --fix", + "git add" + ] + }, + "keywords": [ + "vue", + "admin", + "dashboard", + "element-ui", + "boilerplate", + "admin-template", + "management-system" + ], + "repository": { + "type": "git", + "url": "https://gitee.com/y_project/RuoYi-Vue.git" + }, + "dependencies": { + "@kangc/v-md-editor": "^1.7.11", + "@riophae/vue-treeselect": "0.4.0", + "axios": "0.24.0", + "clipboard": "2.0.8", + "core-js": "3.25.3", + "dayjs": "^1.11.7", + "echarts": "4.9.0", + "element-ui": "2.15.10", + "file-saver": "2.0.5", + "fuse.js": "6.4.3", + "highlight.js": "9.18.5", + "image-conversion": "^2.1.1", + "js-beautify": "1.13.0", + "js-cookie": "3.0.1", + "jsencrypt": "3.0.0-rc.1", + "less-loader": "^5.0.0", + "mavon-editor": "^2.9.0", + "nprogress": "0.2.0", + "path": "^0.12.7", + "quill": "1.3.7", + "screenfull": "5.0.2", + "sortablejs": "1.10.2", + "vue": "2.6.12", + "vue-calendar-heatmap": "^0.8.4", + "vue-count-to": "1.0.13", + "vue-cropper": "0.5.5", + "vue-meta": "2.4.0", + "vue-router": "3.4.9", + "vuedraggable": "2.24.3", + "vuex": "3.6.0" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "4.4.6", + "@vue/cli-plugin-eslint": "4.4.6", + "@vue/cli-service": "4.4.6", + "babel-eslint": "10.1.0", + "babel-plugin-dynamic-import-node": "2.3.3", + "chalk": "4.1.0", + "compression-webpack-plugin": "5.0.2", + "connect": "3.6.6", + "eslint": "7.15.0", + "eslint-plugin-vue": "7.2.0", + "lint-staged": "10.5.3", + "runjs": "4.4.2", + "sass": "1.32.13", + "sass-loader": "10.1.1", + "script-ext-html-webpack-plugin": "2.1.5", + "svg-sprite-loader": "5.1.1", + "vue-template-compiler": "2.6.12" + }, + "engines": { + "node": ">=8.9", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions" + ] +} diff --git a/zhi-admin-ui/public/favicon.ico b/zhi-admin-ui/public/favicon.ico new file mode 100644 index 0000000..71b1dac Binary files /dev/null and b/zhi-admin-ui/public/favicon.ico differ diff --git a/zhi-admin-ui/public/html/ie.html b/zhi-admin-ui/public/html/ie.html new file mode 100644 index 0000000..052ffcd --- /dev/null +++ b/zhi-admin-ui/public/html/ie.html @@ -0,0 +1,46 @@ + + + + + + 请升级您的浏览器 + + + + + + +

请升级您的浏览器,以便我们更好的为您提供服务!

+

您正在使用 Internet Explorer 的早期版本(IE11以下版本或使用该内核的浏览器)。这意味着在升级浏览器前,您将无法访问此网站。

+
+

请注意:微软公司对Windows XP 及 Internet Explorer 早期版本的支持已经结束

+

自 2016 年 1 月 12 日起,Microsoft 不再为 IE 11 以下版本提供相应支持和更新。没有关键的浏览器安全更新,您的电脑可能易受有害病毒、间谍软件和其他恶意软件的攻击,它们可以窃取或损害您的业务数据和信息。请参阅 微软对 Internet Explorer 早期版本的支持将于 2016 年 1 月 12 日结束的说明

+
+

您可以选择更先进的浏览器

+

推荐使用以下浏览器的最新版本。如果您的电脑已有以下浏览器的最新版本则直接使用该浏览器访问即可。

+ +
+ + \ No newline at end of file diff --git a/zhi-admin-ui/public/index.html b/zhi-admin-ui/public/index.html new file mode 100644 index 0000000..05b6745 --- /dev/null +++ b/zhi-admin-ui/public/index.html @@ -0,0 +1,208 @@ + + + + + + + + + <%= webpackConfig.name %> + + + + +
+
+
+
+
+
正在加载系统资源,请耐心等待
+
+
+ + diff --git a/zhi-admin-ui/public/robots.txt b/zhi-admin-ui/public/robots.txt new file mode 100644 index 0000000..77470cb --- /dev/null +++ b/zhi-admin-ui/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / \ No newline at end of file diff --git a/zhi-admin-ui/src/App.vue b/zhi-admin-ui/src/App.vue new file mode 100644 index 0000000..fc1f53c --- /dev/null +++ b/zhi-admin-ui/src/App.vue @@ -0,0 +1,29 @@ + + + + diff --git a/zhi-admin-ui/src/api/about/about.js b/zhi-admin-ui/src/api/about/about.js new file mode 100644 index 0000000..48f3e43 --- /dev/null +++ b/zhi-admin-ui/src/api/about/about.js @@ -0,0 +1,34 @@ +import request from '@/utils/request' + +// 查询关于我的信息 +export function getAbout(query) { + return request({ + url: '/blogInfo/about', + method: 'get', + params: query + }) +} + +// 修改关于我 +export function updateAbout(data) { + return request({ + url: '/blogInfo/admin/about', + method: 'put', + data: data + }) +} + + +//上传富文本编辑器内图片 +export function uploadOssImage(data){ + return request({ + url:'/system/oss/upload', + method:'post', + data:data + }) + +} + + + + diff --git a/zhi-admin-ui/src/api/album/album.js b/zhi-admin-ui/src/api/album/album.js new file mode 100644 index 0000000..790340c --- /dev/null +++ b/zhi-admin-ui/src/api/album/album.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询相册管理列表 +export function listAlbum(query) { + return request({ + url: '/album/album/list', + method: 'get', + params: query + }) +} + +// 查询相册管理详细 +export function getAlbum(id) { + return request({ + url: '/album/album/' + id, + method: 'get' + }) +} + +// 新增相册管理 +export function addAlbum(data) { + return request({ + url: '/album/album', + method: 'post', + data: data + }) +} + +// 修改相册管理 +export function updateAlbum(data) { + return request({ + url: '/album/album', + method: 'put', + data: data + }) +} + +// 删除相册管理 +export function delAlbum(id) { + return request({ + url: '/album/album/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/article/article.js b/zhi-admin-ui/src/api/article/article.js new file mode 100644 index 0000000..bc7f6b8 --- /dev/null +++ b/zhi-admin-ui/src/api/article/article.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询文章列表列表 +export function listArticle(query) { + return request({ + url: '/article/article/list', + method: 'get', + params: query + }) +} + +// 查询文章列表详细 +export function getArticle(id) { + return request({ + url: '/article/article/' + id, + method: 'get' + }) +} + +// 新增文章列表 +export function addArticle(data) { + return request({ + url: '/article/article', + method: 'post', + data: data + }) +} + +// 修改文章列表 +export function updateArticle(data) { + return request({ + url: '/article/article', + method: 'put', + data: data + }) +} + +// 删除文章列表 +export function delArticle(id) { + return request({ + url: '/article/article/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/category/category.js b/zhi-admin-ui/src/api/category/category.js new file mode 100644 index 0000000..faa5d6c --- /dev/null +++ b/zhi-admin-ui/src/api/category/category.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询分类管理列表 +export function listCategory(query) { + return request({ + url: '/category/category/list', + method: 'get', + params: query + }) +} + +// 查询分类管理详细 +export function getCategory(id) { + return request({ + url: '/category/category/' + id, + method: 'get' + }) +} + +// 新增分类管理 +export function addCategory(data) { + return request({ + url: '/category/category', + method: 'post', + data: data + }) +} + +// 修改分类管理 +export function updateCategory(data) { + return request({ + url: '/category/category', + method: 'put', + data: data + }) +} + +// 删除分类管理 +export function delCategory(id) { + return request({ + url: '/category/category/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/comment/comment.js b/zhi-admin-ui/src/api/comment/comment.js new file mode 100644 index 0000000..24a8878 --- /dev/null +++ b/zhi-admin-ui/src/api/comment/comment.js @@ -0,0 +1,55 @@ +import request from '@/utils/request' + +// 查询评论管理列表 +export function listComment(query) { + return request({ + url: '/comment/comment/list', + method: 'get', + params: query + }) +} + +// 查询评论管理详细 +export function getComment(id) { + return request({ + url: '/comment/comment/' + id, + method: 'get' + }) +} + +// 新增评论管理 +export function addComment(data) { + return request({ + url: '/comment/comment', + method: 'post', + data: data + }) +} + +// 修改评论管理 +export function updateComment(data) { + return request({ + url: '/comment/comment', + method: 'put', + data: data + }) +} + +// 删除评论管理 +export function delComment(id) { + return request({ + url: '/comment/comment/' + id, + method: 'delete' + }) + +} + +//审核评论管理 +export function auditComment(query){ + return request({ + url:'/comment/comment/audit', + method: 'get', + params: query + + }) +} diff --git a/zhi-admin-ui/src/api/demo/demo.js b/zhi-admin-ui/src/api/demo/demo.js new file mode 100644 index 0000000..04d4025 --- /dev/null +++ b/zhi-admin-ui/src/api/demo/demo.js @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +// 查询测试单表列表 +export function listDemo(query) { + return request({ + url: '/demo/demo/list', + method: 'get', + params: query + }) +} + +// 自定义分页接口 +export function pageDemo(query) { + return request({ + url: '/demo/demo/page', + method: 'get', + params: query + }) +} + +// 查询测试单表详细 +export function getDemo(id) { + return request({ + url: '/demo/demo/' + id, + method: 'get' + }) +} + +// 新增测试单表 +export function addDemo(data) { + return request({ + url: '/demo/demo', + method: 'post', + data: data + }) +} + +// 修改测试单表 +export function updateDemo(data) { + return request({ + url: '/demo/demo', + method: 'put', + data: data + }) +} + +// 删除测试单表 +export function delDemo(id) { + return request({ + url: '/demo/demo/' + id, + method: 'delete' + }) +} + diff --git a/zhi-admin-ui/src/api/demo/tree.js b/zhi-admin-ui/src/api/demo/tree.js new file mode 100644 index 0000000..4c7ebc0 --- /dev/null +++ b/zhi-admin-ui/src/api/demo/tree.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询测试树表列表 +export function listTree(query) { + return request({ + url: '/demo/tree/list', + method: 'get', + params: query + }) +} + +// 查询测试树表详细 +export function getTree(id) { + return request({ + url: '/demo/tree/' + id, + method: 'get' + }) +} + +// 新增测试树表 +export function addTree(data) { + return request({ + url: '/demo/tree', + method: 'post', + data: data + }) +} + +// 修改测试树表 +export function updateTree(data) { + return request({ + url: '/demo/tree', + method: 'put', + data: data + }) +} + +// 删除测试树表 +export function delTree(id) { + return request({ + url: '/demo/tree/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/friendLink/friendLink.js b/zhi-admin-ui/src/api/friendLink/friendLink.js new file mode 100644 index 0000000..1778f2c --- /dev/null +++ b/zhi-admin-ui/src/api/friendLink/friendLink.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询友链管理列表 +export function listFriendLink(query) { + return request({ + url: '/friendLink/friendLink/list', + method: 'get', + params: query + }) +} + +// 查询友链管理详细 +export function getFriendLink(id) { + return request({ + url: '/friendLink/friendLink/' + id, + method: 'get' + }) +} + +// 新增友链管理 +export function addFriendLink(data) { + return request({ + url: '/friendLink/friendLink', + method: 'post', + data: data + }) +} + +// 修改友链管理 +export function updateFriendLink(data) { + return request({ + url: '/friendLink/friendLink', + method: 'put', + data: data + }) +} + +// 删除友链管理 +export function delFriendLink(id) { + return request({ + url: '/friendLink/friendLink/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/login.js b/zhi-admin-ui/src/api/login.js new file mode 100644 index 0000000..3c5bcfe --- /dev/null +++ b/zhi-admin-ui/src/api/login.js @@ -0,0 +1,71 @@ +import request from '@/utils/request' + +// 登录方法 +export function login(username, password, code, uuid) { + const data = { + username, + password, + code, + uuid + } + return request({ + url: '/login', + headers: { + isToken: false + }, + method: 'post', + data: data + }) +} + +// 注册方法 +export function register(data) { + return request({ + url: '/register', + headers: { + isToken: false + }, + method: 'post', + data: data + }) +} + +// 获取用户详细信息 +export function getInfo() { + return request({ + url: '/getInfo', + method: 'get' + }) +} + +// 退出方法 +export function logout() { + return request({ + url: '/logout', + method: 'post' + }) +} + +// 获取验证码 +export function getCodeImg() { + return request({ + url: '/captchaImage', + headers: { + isToken: false + }, + method: 'get', + timeout: 20000 + }) +} + +// 短信验证码 +export function getCodeSms() { + return request({ + url: '/captchaSms', + headers: { + isToken: false + }, + method: 'get', + timeout: 20000 + }) +} diff --git a/zhi-admin-ui/src/api/menu.js b/zhi-admin-ui/src/api/menu.js new file mode 100644 index 0000000..faef101 --- /dev/null +++ b/zhi-admin-ui/src/api/menu.js @@ -0,0 +1,9 @@ +import request from '@/utils/request' + +// 获取路由 +export const getRouters = () => { + return request({ + url: '/getRouters', + method: 'get' + }) +} \ No newline at end of file diff --git a/zhi-admin-ui/src/api/message/message.js b/zhi-admin-ui/src/api/message/message.js new file mode 100644 index 0000000..b6cdc15 --- /dev/null +++ b/zhi-admin-ui/src/api/message/message.js @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 查询留言管理列表 +export function listMessage(query) { + return request({ + url: '/message/message/list', + method: 'get', + params: query + }) +} + +// 查询留言管理详细 +export function getMessage(id) { + return request({ + url: '/message/message/' + id, + method: 'get' + }) +} + +// 新增留言管理 +export function addMessage(data) { + return request({ + url: '/message/message', + method: 'post', + data: data + }) +} + +// 修改留言管理 +export function updateMessage(data) { + return request({ + url: '/message/message', + method: 'put', + data: data + }) +} + +// 删除留言管理 +export function delMessage(id) { + return request({ + url: '/message/message/' + id, + method: 'delete' + }) +} + +// 审核留言管理 +export function auditMessage(query){ + return request({ + url:'/message/message/audit', + method: 'get', + params: query + }) +} diff --git a/zhi-admin-ui/src/api/monitor/cache.js b/zhi-admin-ui/src/api/monitor/cache.js new file mode 100644 index 0000000..5cf0517 --- /dev/null +++ b/zhi-admin-ui/src/api/monitor/cache.js @@ -0,0 +1,57 @@ +import request from '@/utils/request' + +// 查询缓存详细 +export function getCache() { + return request({ + url: '/monitor/cache', + method: 'get' + }) +} + +// 查询缓存名称列表 +export function listCacheName() { + return request({ + url: '/monitor/cache/getNames', + method: 'get' + }) +} + +// 查询缓存键名列表 +export function listCacheKey(cacheName) { + return request({ + url: '/monitor/cache/getKeys/' + cacheName, + method: 'get' + }) +} + +// 查询缓存内容 +export function getCacheValue(cacheName, cacheKey) { + return request({ + url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey, + method: 'get' + }) +} + +// 清理指定名称缓存 +export function clearCacheName(cacheName) { + return request({ + url: '/monitor/cache/clearCacheName/' + cacheName, + method: 'delete' + }) +} + +// 清理指定键名缓存 +export function clearCacheKey(cacheName, cacheKey) { + return request({ + url: '/monitor/cache/clearCacheKey/'+ cacheName + "/" + cacheKey, + method: 'delete' + }) +} + +// 清理全部缓存 +export function clearCacheAll() { + return request({ + url: '/monitor/cache/clearCacheAll', + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/monitor/logininfor.js b/zhi-admin-ui/src/api/monitor/logininfor.js new file mode 100644 index 0000000..4d112b7 --- /dev/null +++ b/zhi-admin-ui/src/api/monitor/logininfor.js @@ -0,0 +1,34 @@ +import request from '@/utils/request' + +// 查询登录日志列表 +export function list(query) { + return request({ + url: '/monitor/logininfor/list', + method: 'get', + params: query + }) +} + +// 删除登录日志 +export function delLogininfor(infoId) { + return request({ + url: '/monitor/logininfor/' + infoId, + method: 'delete' + }) +} + +// 解锁用户登录状态 +export function unlockLogininfor(userName) { + return request({ + url: '/monitor/logininfor/unlock/' + userName, + method: 'get' + }) +} + +// 清空登录日志 +export function cleanLogininfor() { + return request({ + url: '/monitor/logininfor/clean', + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/monitor/online.js b/zhi-admin-ui/src/api/monitor/online.js new file mode 100644 index 0000000..bd22137 --- /dev/null +++ b/zhi-admin-ui/src/api/monitor/online.js @@ -0,0 +1,18 @@ +import request from '@/utils/request' + +// 查询在线用户列表 +export function list(query) { + return request({ + url: '/monitor/online/list', + method: 'get', + params: query + }) +} + +// 强退用户 +export function forceLogout(tokenId) { + return request({ + url: '/monitor/online/' + tokenId, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/monitor/operlog.js b/zhi-admin-ui/src/api/monitor/operlog.js new file mode 100644 index 0000000..a04bca8 --- /dev/null +++ b/zhi-admin-ui/src/api/monitor/operlog.js @@ -0,0 +1,26 @@ +import request from '@/utils/request' + +// 查询操作日志列表 +export function list(query) { + return request({ + url: '/monitor/operlog/list', + method: 'get', + params: query + }) +} + +// 删除操作日志 +export function delOperlog(operId) { + return request({ + url: '/monitor/operlog/' + operId, + method: 'delete' + }) +} + +// 清空操作日志 +export function cleanOperlog() { + return request({ + url: '/monitor/operlog/clean', + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/page/page.js b/zhi-admin-ui/src/api/page/page.js new file mode 100644 index 0000000..3e0052b --- /dev/null +++ b/zhi-admin-ui/src/api/page/page.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询页面管理列表 +export function listPage(query) { + return request({ + url: '/page/page/list', + method: 'get', + params: query + }) +} + +// 查询页面管理详细 +export function getPage(id) { + return request({ + url: '/page/page/' + id, + method: 'get' + }) +} + +// 新增页面管理 +export function addPage(data) { + return request({ + url: '/page/page', + method: 'post', + data: data + }) +} + +// 修改页面管理 +export function updatePage(data) { + return request({ + url: '/page/page', + method: 'put', + data: data + }) +} + +// 删除页面管理 +export function delPage(id) { + return request({ + url: '/page/page/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/photo/photo.js b/zhi-admin-ui/src/api/photo/photo.js new file mode 100644 index 0000000..f3df85a --- /dev/null +++ b/zhi-admin-ui/src/api/photo/photo.js @@ -0,0 +1,54 @@ +import request from '@/utils/request' + +// 查询照片管理列表 +export function listPhoto(query) { + return request({ + url: '/photo/photo/list', + method: 'get', + params: query + }) +} + +// 查询照片管理详细 +export function getPhoto(id) { + return request({ + url: '/photo/photo/' + id, + method: 'get' + }) +} + +// 新增照片管理 +export function addPhoto(data) { + return request({ + url: '/photo/photo', + method: 'post', + data: data + }) +} + +// 修改照片管理 +export function updatePhoto(data) { + return request({ + url: '/photo/photo', + method: 'put', + data: data + }) +} + +// 修改照片所属相册 +export function updatePhotoAlbum(data) { + return request({ + url: '/photo/photo/album', + method: 'put', + data: data + }) +} + + +// 删除照片管理 +export function delPhoto(id) { + return request({ + url: '/photo/photo/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/system/config.js b/zhi-admin-ui/src/api/system/config.js new file mode 100644 index 0000000..02f0cfc --- /dev/null +++ b/zhi-admin-ui/src/api/system/config.js @@ -0,0 +1,73 @@ +import request from '@/utils/request' + +// 查询参数列表 +export function listConfig(query) { + return request({ + url: '/system/config/list', + method: 'get', + params: query + }) +} + +// 查询参数详细 +export function getConfig(configId) { + return request({ + url: '/system/config/' + configId, + method: 'get' + }) +} + +// 根据参数键名查询参数值 +export function getConfigKey(configKey) { + return request({ + url: '/system/config/configKey/' + configKey, + method: 'get' + }) +} + +// 新增参数配置 +export function addConfig(data) { + return request({ + url: '/system/config', + method: 'post', + data: data + }) +} + +// 修改参数配置 +export function updateConfig(data) { + return request({ + url: '/system/config', + method: 'put', + data: data + }) +} + +// 修改参数配置 +export function updateConfigByKey(key, value) { + return request({ + url: '/system/config/updateByKey', + method: 'put', + data: { + configKey: key, + configValue: value + } + }) +} + +// 删除参数配置 +export function delConfig(configId) { + return request({ + url: '/system/config/' + configId, + method: 'delete' + }) +} + +// 刷新参数缓存 +export function refreshCache() { + return request({ + url: '/system/config/refreshCache', + method: 'delete' + }) +} + diff --git a/zhi-admin-ui/src/api/system/dept.js b/zhi-admin-ui/src/api/system/dept.js new file mode 100644 index 0000000..331c4b2 --- /dev/null +++ b/zhi-admin-ui/src/api/system/dept.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询部门列表 +export function listDept(query) { + return request({ + url: '/system/dept/list', + method: 'get', + params: query + }) +} + +// 查询部门列表(排除节点) +export function listDeptExcludeChild(deptId) { + return request({ + url: '/system/dept/list/exclude/' + deptId, + method: 'get' + }) +} + +// 查询部门详细 +export function getDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'get' + }) +} + +// 新增部门 +export function addDept(data) { + return request({ + url: '/system/dept', + method: 'post', + data: data + }) +} + +// 修改部门 +export function updateDept(data) { + return request({ + url: '/system/dept', + method: 'put', + data: data + }) +} + +// 删除部门 +export function delDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/system/dict/data.js b/zhi-admin-ui/src/api/system/dict/data.js new file mode 100644 index 0000000..6c9eb79 --- /dev/null +++ b/zhi-admin-ui/src/api/system/dict/data.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询字典数据列表 +export function listData(query) { + return request({ + url: '/system/dict/data/list', + method: 'get', + params: query + }) +} + +// 查询字典数据详细 +export function getData(dictCode) { + return request({ + url: '/system/dict/data/' + dictCode, + method: 'get' + }) +} + +// 根据字典类型查询字典数据信息 +export function getDicts(dictType) { + return request({ + url: '/system/dict/data/type/' + dictType, + method: 'get' + }) +} + +// 新增字典数据 +export function addData(data) { + return request({ + url: '/system/dict/data', + method: 'post', + data: data + }) +} + +// 修改字典数据 +export function updateData(data) { + return request({ + url: '/system/dict/data', + method: 'put', + data: data + }) +} + +// 删除字典数据 +export function delData(dictCode) { + return request({ + url: '/system/dict/data/' + dictCode, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/system/dict/type.js b/zhi-admin-ui/src/api/system/dict/type.js new file mode 100644 index 0000000..a0254ba --- /dev/null +++ b/zhi-admin-ui/src/api/system/dict/type.js @@ -0,0 +1,60 @@ +import request from '@/utils/request' + +// 查询字典类型列表 +export function listType(query) { + return request({ + url: '/system/dict/type/list', + method: 'get', + params: query + }) +} + +// 查询字典类型详细 +export function getType(dictId) { + return request({ + url: '/system/dict/type/' + dictId, + method: 'get' + }) +} + +// 新增字典类型 +export function addType(data) { + return request({ + url: '/system/dict/type', + method: 'post', + data: data + }) +} + +// 修改字典类型 +export function updateType(data) { + return request({ + url: '/system/dict/type', + method: 'put', + data: data + }) +} + +// 删除字典类型 +export function delType(dictId) { + return request({ + url: '/system/dict/type/' + dictId, + method: 'delete' + }) +} + +// 刷新字典缓存 +export function refreshCache() { + return request({ + url: '/system/dict/type/refreshCache', + method: 'delete' + }) +} + +// 获取字典选择框列表 +export function optionselect() { + return request({ + url: '/system/dict/type/optionselect', + method: 'get' + }) +} diff --git a/zhi-admin-ui/src/api/system/menu.js b/zhi-admin-ui/src/api/system/menu.js new file mode 100644 index 0000000..f6415c6 --- /dev/null +++ b/zhi-admin-ui/src/api/system/menu.js @@ -0,0 +1,60 @@ +import request from '@/utils/request' + +// 查询菜单列表 +export function listMenu(query) { + return request({ + url: '/system/menu/list', + method: 'get', + params: query + }) +} + +// 查询菜单详细 +export function getMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'get' + }) +} + +// 查询菜单下拉树结构 +export function treeselect() { + return request({ + url: '/system/menu/treeselect', + method: 'get' + }) +} + +// 根据角色ID查询菜单下拉树结构 +export function roleMenuTreeselect(roleId) { + return request({ + url: '/system/menu/roleMenuTreeselect/' + roleId, + method: 'get' + }) +} + +// 新增菜单 +export function addMenu(data) { + return request({ + url: '/system/menu', + method: 'post', + data: data + }) +} + +// 修改菜单 +export function updateMenu(data) { + return request({ + url: '/system/menu', + method: 'put', + data: data + }) +} + +// 删除菜单 +export function delMenu(menuId) { + return request({ + url: '/system/menu/' + menuId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/zhi-admin-ui/src/api/system/notice.js b/zhi-admin-ui/src/api/system/notice.js new file mode 100644 index 0000000..c274ea5 --- /dev/null +++ b/zhi-admin-ui/src/api/system/notice.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询公告列表 +export function listNotice(query) { + return request({ + url: '/system/notice/list', + method: 'get', + params: query + }) +} + +// 查询公告详细 +export function getNotice(noticeId) { + return request({ + url: '/system/notice/' + noticeId, + method: 'get' + }) +} + +// 新增公告 +export function addNotice(data) { + return request({ + url: '/system/notice', + method: 'post', + data: data + }) +} + +// 修改公告 +export function updateNotice(data) { + return request({ + url: '/system/notice', + method: 'put', + data: data + }) +} + +// 删除公告 +export function delNotice(noticeId) { + return request({ + url: '/system/notice/' + noticeId, + method: 'delete' + }) +} \ No newline at end of file diff --git a/zhi-admin-ui/src/api/system/oss.js b/zhi-admin-ui/src/api/system/oss.js new file mode 100644 index 0000000..7d80026 --- /dev/null +++ b/zhi-admin-ui/src/api/system/oss.js @@ -0,0 +1,27 @@ +import request from '@/utils/request' + +// 查询OSS对象存储列表 +export function listOss(query) { + return request({ + url: '/system/oss/list', + method: 'get', + params: query + }) +} + +// 查询OSS对象基于id串 +export function listByIds(ossId) { + return request({ + url: '/system/oss/listByIds/' + ossId, + method: 'get' + }) +} + +// 删除OSS对象存储 +export function delOss(ossId) { + return request({ + url: '/system/oss/' + ossId, + method: 'delete' + }) +} + diff --git a/zhi-admin-ui/src/api/system/ossConfig.js b/zhi-admin-ui/src/api/system/ossConfig.js new file mode 100644 index 0000000..f290762 --- /dev/null +++ b/zhi-admin-ui/src/api/system/ossConfig.js @@ -0,0 +1,58 @@ +import request from '@/utils/request' + +// 查询对象存储配置列表 +export function listOssConfig(query) { + return request({ + url: '/system/oss/config/list', + method: 'get', + params: query + }) +} + +// 查询对象存储配置详细 +export function getOssConfig(ossConfigId) { + return request({ + url: '/system/oss/config/' + ossConfigId, + method: 'get' + }) +} + +// 新增对象存储配置 +export function addOssConfig(data) { + return request({ + url: '/system/oss/config', + method: 'post', + data: data + }) +} + +// 修改对象存储配置 +export function updateOssConfig(data) { + return request({ + url: '/system/oss/config', + method: 'put', + data: data + }) +} + +// 删除对象存储配置 +export function delOssConfig(ossConfigId) { + return request({ + url: '/system/oss/config/' + ossConfigId, + method: 'delete' + }) +} + +// 对象存储状态修改 +export function changeOssConfigStatus(ossConfigId, status, configKey) { + const data = { + ossConfigId, + status, + configKey + } + return request({ + url: '/system/oss/config/changeStatus', + method: 'put', + data: data + }) +} diff --git a/zhi-admin-ui/src/api/system/post.js b/zhi-admin-ui/src/api/system/post.js new file mode 100644 index 0000000..1a8e9ca --- /dev/null +++ b/zhi-admin-ui/src/api/system/post.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询岗位列表 +export function listPost(query) { + return request({ + url: '/system/post/list', + method: 'get', + params: query + }) +} + +// 查询岗位详细 +export function getPost(postId) { + return request({ + url: '/system/post/' + postId, + method: 'get' + }) +} + +// 新增岗位 +export function addPost(data) { + return request({ + url: '/system/post', + method: 'post', + data: data + }) +} + +// 修改岗位 +export function updatePost(data) { + return request({ + url: '/system/post', + method: 'put', + data: data + }) +} + +// 删除岗位 +export function delPost(postId) { + return request({ + url: '/system/post/' + postId, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/system/role.js b/zhi-admin-ui/src/api/system/role.js new file mode 100644 index 0000000..f13e6f4 --- /dev/null +++ b/zhi-admin-ui/src/api/system/role.js @@ -0,0 +1,119 @@ +import request from '@/utils/request' + +// 查询角色列表 +export function listRole(query) { + return request({ + url: '/system/role/list', + method: 'get', + params: query + }) +} + +// 查询角色详细 +export function getRole(roleId) { + return request({ + url: '/system/role/' + roleId, + method: 'get' + }) +} + +// 新增角色 +export function addRole(data) { + return request({ + url: '/system/role', + method: 'post', + data: data + }) +} + +// 修改角色 +export function updateRole(data) { + return request({ + url: '/system/role', + method: 'put', + data: data + }) +} + +// 角色数据权限 +export function dataScope(data) { + return request({ + url: '/system/role/dataScope', + method: 'put', + data: data + }) +} + +// 角色状态修改 +export function changeRoleStatus(roleId, status) { + const data = { + roleId, + status + } + return request({ + url: '/system/role/changeStatus', + method: 'put', + data: data + }) +} + +// 删除角色 +export function delRole(roleId) { + return request({ + url: '/system/role/' + roleId, + method: 'delete' + }) +} + +// 查询角色已授权用户列表 +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 + }) +} + +// 根据角色ID查询部门树结构 +export function deptTreeSelect(roleId) { + return request({ + url: '/system/role/deptTree/' + roleId, + method: 'get' + }) +} diff --git a/zhi-admin-ui/src/api/system/user.js b/zhi-admin-ui/src/api/system/user.js new file mode 100644 index 0000000..f2f76ef --- /dev/null +++ b/zhi-admin-ui/src/api/system/user.js @@ -0,0 +1,135 @@ +import request from '@/utils/request' +import { parseStrEmpty } from "@/utils/ruoyi"; + +// 查询用户列表 +export function listUser(query) { + return request({ + url: '/system/user/list', + method: 'get', + params: query + }) +} + +// 查询用户详细 +export function getUser(userId) { + return request({ + url: '/system/user/' + parseStrEmpty(userId), + method: 'get' + }) +} + +// 新增用户 +export function addUser(data) { + return request({ + url: '/system/user', + method: 'post', + data: data + }) +} + +// 修改用户 +export function updateUser(data) { + return request({ + url: '/system/user', + method: 'put', + data: data + }) +} + +// 删除用户 +export function delUser(userId) { + return request({ + url: '/system/user/' + userId, + method: 'delete' + }) +} + +// 用户密码重置 +export function resetUserPwd(userId, password) { + const data = { + userId, + password + } + return request({ + url: '/system/user/resetPwd', + method: 'put', + data: data + }) +} + +// 用户状态修改 +export function changeUserStatus(userId, status) { + const data = { + userId, + status + } + return request({ + url: '/system/user/changeStatus', + method: 'put', + data: data + }) +} + +// 查询用户个人信息 +export function getUserProfile() { + return request({ + url: '/system/user/profile', + method: 'get' + }) +} + +// 修改用户个人信息 +export function updateUserProfile(data) { + return request({ + url: '/system/user/profile', + method: 'put', + data: data + }) +} + +// 用户密码重置 +export function updateUserPwd(oldPassword, newPassword) { + const data = { + oldPassword, + newPassword + } + return request({ + url: '/system/user/profile/updatePwd', + method: 'put', + params: data + }) +} + +// 用户头像上传 +export function uploadAvatar(data) { + return request({ + url: '/system/user/profile/avatar', + method: 'post', + data: data + }) +} + +// 查询授权角色 +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 + }) +} + +// 查询部门下拉树结构 +export function deptTreeSelect() { + return request({ + url: '/system/user/deptTree', + method: 'get' + }) +} diff --git a/zhi-admin-ui/src/api/tag/tag.js b/zhi-admin-ui/src/api/tag/tag.js new file mode 100644 index 0000000..4e0aeba --- /dev/null +++ b/zhi-admin-ui/src/api/tag/tag.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询标签管理列表 +export function listTag(query) { + return request({ + url: '/tag/tag/list', + method: 'get', + params: query + }) +} + +// 查询标签管理详细 +export function getTag(id) { + return request({ + url: '/tag/tag/' + id, + method: 'get' + }) +} + +// 新增标签管理 +export function addTag(data) { + return request({ + url: '/tag/tag', + method: 'post', + data: data + }) +} + +// 修改标签管理 +export function updateTag(data) { + return request({ + url: '/tag/tag', + method: 'put', + data: data + }) +} + +// 删除标签管理 +export function delTag(id) { + return request({ + url: '/tag/tag/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/talk/talk.js b/zhi-admin-ui/src/api/talk/talk.js new file mode 100644 index 0000000..d02f959 --- /dev/null +++ b/zhi-admin-ui/src/api/talk/talk.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询说说管理列表 +export function listTalk(query) { + return request({ + url: '/talk/talk/list', + method: 'get', + params: query + }) +} + +// 查询说说管理详细 +export function getTalk(id) { + return request({ + url: '/talk/talk/' + id, + method: 'get' + }) +} + +// 新增说说管理 +export function addTalk(data) { + return request({ + url: '/talk/talk', + method: 'post', + data: data + }) +} + +// 修改说说管理 +export function updateTalk(data) { + return request({ + url: '/talk/talk', + method: 'put', + data: data + }) +} + +// 删除说说管理 +export function delTalk(id) { + return request({ + url: '/talk/talk/' + id, + method: 'delete' + }) +} diff --git a/zhi-admin-ui/src/api/tool/gen.js b/zhi-admin-ui/src/api/tool/gen.js new file mode 100644 index 0000000..65ddfea --- /dev/null +++ b/zhi-admin-ui/src/api/tool/gen.js @@ -0,0 +1,86 @@ +import request from '@/utils/request' + +// 查询生成表数据 +export function listTable(query) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/list', + method: 'get', + params: query + }) +} + +// 查询db数据库列表 +export function listDbTable(query) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/db/list', + method: 'get', + params: query + }) +} + +// 查询表详细信息 +export function getGenTable(tableId) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/' + tableId, + method: 'get' + }) +} + +// 修改代码生成信息 +export function updateGenTable(data) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen', + method: 'put', + data: data + }) +} + +// 导入表 +export function importTable(data) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/importTable', + method: 'post', + params: data + }) +} + +// 预览生成代码 +export function previewTable(tableId) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/preview/' + tableId, + method: 'get' + }) +} + +// 删除表数据 +export function delTable(tableId) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/' + tableId, + method: 'delete' + }) +} + +// 生成代码(自定义路径) +export function genCode(tableName) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/genCode/' + tableName, + method: 'get' + }) +} + +// 同步数据库 +export function synchDb(tableName) { + return request({ + headers: { 'datasource': localStorage.getItem("dataName") }, + url: '/tool/gen/synchDb/' + tableName, + method: 'get' + }) +} diff --git a/zhi-admin-ui/src/api/website/website.js b/zhi-admin-ui/src/api/website/website.js new file mode 100644 index 0000000..566503b --- /dev/null +++ b/zhi-admin-ui/src/api/website/website.js @@ -0,0 +1,20 @@ +import request from '@/utils/request' + +// 查询标签管理列表 +export function getWebsiteConfig(query) { + return request({ + url: '/website/admin/config', + method: 'get', + params: query + }) +} + + +export function updateWebsiteConfig(data) { + return request({ + url: 'website/config', + method: 'put', + data: data + }) + +} diff --git a/zhi-admin-ui/src/assets/401_images/401.gif b/zhi-admin-ui/src/assets/401_images/401.gif new file mode 100644 index 0000000..cd6e0d9 Binary files /dev/null and b/zhi-admin-ui/src/assets/401_images/401.gif differ diff --git a/zhi-admin-ui/src/assets/404_images/404.png b/zhi-admin-ui/src/assets/404_images/404.png new file mode 100644 index 0000000..3d8e230 Binary files /dev/null and b/zhi-admin-ui/src/assets/404_images/404.png differ diff --git a/zhi-admin-ui/src/assets/404_images/404_cloud.png b/zhi-admin-ui/src/assets/404_images/404_cloud.png new file mode 100644 index 0000000..c6281d0 Binary files /dev/null and b/zhi-admin-ui/src/assets/404_images/404_cloud.png differ diff --git a/zhi-admin-ui/src/assets/icons/index.js b/zhi-admin-ui/src/assets/icons/index.js new file mode 100644 index 0000000..2c6b309 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/index.js @@ -0,0 +1,9 @@ +import Vue from 'vue' +import SvgIcon from '@/components/SvgIcon'// svg component + +// register globally +Vue.component('svg-icon', SvgIcon) + +const req = require.context('./svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys().map(requireContext) +requireAll(req) diff --git a/zhi-admin-ui/src/assets/icons/svg/404.svg b/zhi-admin-ui/src/assets/icons/svg/404.svg new file mode 100644 index 0000000..6df5019 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/404.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/bug.svg b/zhi-admin-ui/src/assets/icons/svg/bug.svg new file mode 100644 index 0000000..05a150d --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/bug.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/build.svg b/zhi-admin-ui/src/assets/icons/svg/build.svg new file mode 100644 index 0000000..97c4688 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/build.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/button.svg b/zhi-admin-ui/src/assets/icons/svg/button.svg new file mode 100644 index 0000000..904fddc --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/button.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/cascader.svg b/zhi-admin-ui/src/assets/icons/svg/cascader.svg new file mode 100644 index 0000000..e256024 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/cascader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/chart.svg b/zhi-admin-ui/src/assets/icons/svg/chart.svg new file mode 100644 index 0000000..27728fb --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/chart.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/checkbox.svg b/zhi-admin-ui/src/assets/icons/svg/checkbox.svg new file mode 100644 index 0000000..013fd3a --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/checkbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/clipboard.svg b/zhi-admin-ui/src/assets/icons/svg/clipboard.svg new file mode 100644 index 0000000..90923ff --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/clipboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/code.svg b/zhi-admin-ui/src/assets/icons/svg/code.svg new file mode 100644 index 0000000..5f9c5ab --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/code.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/color.svg b/zhi-admin-ui/src/assets/icons/svg/color.svg new file mode 100644 index 0000000..44a81aa --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/color.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/component.svg b/zhi-admin-ui/src/assets/icons/svg/component.svg new file mode 100644 index 0000000..29c3458 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/component.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/dashboard.svg b/zhi-admin-ui/src/assets/icons/svg/dashboard.svg new file mode 100644 index 0000000..5317d37 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/date-range.svg b/zhi-admin-ui/src/assets/icons/svg/date-range.svg new file mode 100644 index 0000000..fda571e --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/date-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/date.svg b/zhi-admin-ui/src/assets/icons/svg/date.svg new file mode 100644 index 0000000..52dc73e --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/date.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/dict.svg b/zhi-admin-ui/src/assets/icons/svg/dict.svg new file mode 100644 index 0000000..4849377 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/dict.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/documentation.svg b/zhi-admin-ui/src/assets/icons/svg/documentation.svg new file mode 100644 index 0000000..7043122 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/documentation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/download.svg b/zhi-admin-ui/src/assets/icons/svg/download.svg new file mode 100644 index 0000000..c896951 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/drag.svg b/zhi-admin-ui/src/assets/icons/svg/drag.svg new file mode 100644 index 0000000..4185d3c --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/drag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/druid.svg b/zhi-admin-ui/src/assets/icons/svg/druid.svg new file mode 100644 index 0000000..a2b4b4e --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/druid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/edit.svg b/zhi-admin-ui/src/assets/icons/svg/edit.svg new file mode 100644 index 0000000..d26101f --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/education.svg b/zhi-admin-ui/src/assets/icons/svg/education.svg new file mode 100644 index 0000000..7bfb01d --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/education.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/email.svg b/zhi-admin-ui/src/assets/icons/svg/email.svg new file mode 100644 index 0000000..74d25e2 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/email.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/example.svg b/zhi-admin-ui/src/assets/icons/svg/example.svg new file mode 100644 index 0000000..46f42b5 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/excel.svg b/zhi-admin-ui/src/assets/icons/svg/excel.svg new file mode 100644 index 0000000..74d97b8 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/excel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/exit-fullscreen.svg b/zhi-admin-ui/src/assets/icons/svg/exit-fullscreen.svg new file mode 100644 index 0000000..485c128 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/exit-fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/eye-open.svg b/zhi-admin-ui/src/assets/icons/svg/eye-open.svg new file mode 100644 index 0000000..88dcc98 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/eye-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/eye.svg b/zhi-admin-ui/src/assets/icons/svg/eye.svg new file mode 100644 index 0000000..16ed2d8 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/eye.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/form.svg b/zhi-admin-ui/src/assets/icons/svg/form.svg new file mode 100644 index 0000000..dcbaa18 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/fullscreen.svg b/zhi-admin-ui/src/assets/icons/svg/fullscreen.svg new file mode 100644 index 0000000..0e86b6f --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/github.svg b/zhi-admin-ui/src/assets/icons/svg/github.svg new file mode 100644 index 0000000..db0a0d4 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/guide.svg b/zhi-admin-ui/src/assets/icons/svg/guide.svg new file mode 100644 index 0000000..b271001 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/guide.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/icon.svg b/zhi-admin-ui/src/assets/icons/svg/icon.svg new file mode 100644 index 0000000..82be8ee --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/input.svg b/zhi-admin-ui/src/assets/icons/svg/input.svg new file mode 100644 index 0000000..ab91381 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/input.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/international.svg b/zhi-admin-ui/src/assets/icons/svg/international.svg new file mode 100644 index 0000000..e9b56ee --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/international.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/job.svg b/zhi-admin-ui/src/assets/icons/svg/job.svg new file mode 100644 index 0000000..2a93a25 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/job.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/language.svg b/zhi-admin-ui/src/assets/icons/svg/language.svg new file mode 100644 index 0000000..0082b57 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/link.svg b/zhi-admin-ui/src/assets/icons/svg/link.svg new file mode 100644 index 0000000..48197ba --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/list.svg b/zhi-admin-ui/src/assets/icons/svg/list.svg new file mode 100644 index 0000000..20259ed --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/lock.svg b/zhi-admin-ui/src/assets/icons/svg/lock.svg new file mode 100644 index 0000000..74fee54 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/log.svg b/zhi-admin-ui/src/assets/icons/svg/log.svg new file mode 100644 index 0000000..d879d33 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/log.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/logininfor.svg b/zhi-admin-ui/src/assets/icons/svg/logininfor.svg new file mode 100644 index 0000000..267f844 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/logininfor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/message.svg b/zhi-admin-ui/src/assets/icons/svg/message.svg new file mode 100644 index 0000000..14ca817 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/message.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/money.svg b/zhi-admin-ui/src/assets/icons/svg/money.svg new file mode 100644 index 0000000..c1580de --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/money.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/monitor.svg b/zhi-admin-ui/src/assets/icons/svg/monitor.svg new file mode 100644 index 0000000..bc308cb --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/monitor.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/nested.svg b/zhi-admin-ui/src/assets/icons/svg/nested.svg new file mode 100644 index 0000000..06713a8 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/nested.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/number.svg b/zhi-admin-ui/src/assets/icons/svg/number.svg new file mode 100644 index 0000000..ad5ce9a --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/number.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/online.svg b/zhi-admin-ui/src/assets/icons/svg/online.svg new file mode 100644 index 0000000..330a202 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/online.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/password.svg b/zhi-admin-ui/src/assets/icons/svg/password.svg new file mode 100644 index 0000000..6c64def --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/password.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/pdf.svg b/zhi-admin-ui/src/assets/icons/svg/pdf.svg new file mode 100644 index 0000000..957aa0c --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/pdf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/people.svg b/zhi-admin-ui/src/assets/icons/svg/people.svg new file mode 100644 index 0000000..2bd54ae --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/people.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/peoples.svg b/zhi-admin-ui/src/assets/icons/svg/peoples.svg new file mode 100644 index 0000000..aab852e --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/peoples.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/phone.svg b/zhi-admin-ui/src/assets/icons/svg/phone.svg new file mode 100644 index 0000000..ab8e8c4 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/phone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/post.svg b/zhi-admin-ui/src/assets/icons/svg/post.svg new file mode 100644 index 0000000..2922c61 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/post.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/qq.svg b/zhi-admin-ui/src/assets/icons/svg/qq.svg new file mode 100644 index 0000000..ee13d4e --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/qq.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/question.svg b/zhi-admin-ui/src/assets/icons/svg/question.svg new file mode 100644 index 0000000..cf75bd4 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/question.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/radio.svg b/zhi-admin-ui/src/assets/icons/svg/radio.svg new file mode 100644 index 0000000..0cde345 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/radio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/rate.svg b/zhi-admin-ui/src/assets/icons/svg/rate.svg new file mode 100644 index 0000000..aa3b14d --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/rate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/redis-list.svg b/zhi-admin-ui/src/assets/icons/svg/redis-list.svg new file mode 100644 index 0000000..98a15b2 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/redis-list.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/redis.svg b/zhi-admin-ui/src/assets/icons/svg/redis.svg new file mode 100644 index 0000000..2f1d62d --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/redis.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/row.svg b/zhi-admin-ui/src/assets/icons/svg/row.svg new file mode 100644 index 0000000..0780992 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/row.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/search.svg b/zhi-admin-ui/src/assets/icons/svg/search.svg new file mode 100644 index 0000000..84233dd --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/select.svg b/zhi-admin-ui/src/assets/icons/svg/select.svg new file mode 100644 index 0000000..d628382 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/select.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/server.svg b/zhi-admin-ui/src/assets/icons/svg/server.svg new file mode 100644 index 0000000..eb287e3 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/server.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/shopping.svg b/zhi-admin-ui/src/assets/icons/svg/shopping.svg new file mode 100644 index 0000000..87513e7 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/shopping.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/size.svg b/zhi-admin-ui/src/assets/icons/svg/size.svg new file mode 100644 index 0000000..ddb25b8 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/size.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/skill.svg b/zhi-admin-ui/src/assets/icons/svg/skill.svg new file mode 100644 index 0000000..a3b7312 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/skill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/slider.svg b/zhi-admin-ui/src/assets/icons/svg/slider.svg new file mode 100644 index 0000000..fbe4f39 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/slider.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/star.svg b/zhi-admin-ui/src/assets/icons/svg/star.svg new file mode 100644 index 0000000..6cf86e6 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/swagger.svg b/zhi-admin-ui/src/assets/icons/svg/swagger.svg new file mode 100644 index 0000000..05d4e7b --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/swagger.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/switch.svg b/zhi-admin-ui/src/assets/icons/svg/switch.svg new file mode 100644 index 0000000..0ba61e3 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/switch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/system.svg b/zhi-admin-ui/src/assets/icons/svg/system.svg new file mode 100644 index 0000000..5992593 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/system.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/tab.svg b/zhi-admin-ui/src/assets/icons/svg/tab.svg new file mode 100644 index 0000000..b4b48e4 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/tab.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/table.svg b/zhi-admin-ui/src/assets/icons/svg/table.svg new file mode 100644 index 0000000..0e3dc9d --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/textarea.svg b/zhi-admin-ui/src/assets/icons/svg/textarea.svg new file mode 100644 index 0000000..2709f29 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/textarea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/theme.svg b/zhi-admin-ui/src/assets/icons/svg/theme.svg new file mode 100644 index 0000000..5982a2f --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/theme.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/time-range.svg b/zhi-admin-ui/src/assets/icons/svg/time-range.svg new file mode 100644 index 0000000..13c1202 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/time-range.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/time.svg b/zhi-admin-ui/src/assets/icons/svg/time.svg new file mode 100644 index 0000000..b376e32 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/tool.svg b/zhi-admin-ui/src/assets/icons/svg/tool.svg new file mode 100644 index 0000000..48e0e35 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/tool.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/tree-table.svg b/zhi-admin-ui/src/assets/icons/svg/tree-table.svg new file mode 100644 index 0000000..8aafdb8 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/tree-table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/tree.svg b/zhi-admin-ui/src/assets/icons/svg/tree.svg new file mode 100644 index 0000000..dd4b7dd --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/upload.svg b/zhi-admin-ui/src/assets/icons/svg/upload.svg new file mode 100644 index 0000000..bae49c0 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/user.svg b/zhi-admin-ui/src/assets/icons/svg/user.svg new file mode 100644 index 0000000..0ba0716 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/validCode.svg b/zhi-admin-ui/src/assets/icons/svg/validCode.svg new file mode 100644 index 0000000..cfb1021 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/validCode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/wechat.svg b/zhi-admin-ui/src/assets/icons/svg/wechat.svg new file mode 100644 index 0000000..c586e55 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/wechat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svg/zip.svg b/zhi-admin-ui/src/assets/icons/svg/zip.svg new file mode 100644 index 0000000..f806fc4 --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svg/zip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/icons/svgo.yml b/zhi-admin-ui/src/assets/icons/svgo.yml new file mode 100644 index 0000000..d11906a --- /dev/null +++ b/zhi-admin-ui/src/assets/icons/svgo.yml @@ -0,0 +1,22 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + +- removeAttrs: + attrs: + - 'fill' + - 'fill-rule' diff --git a/zhi-admin-ui/src/assets/images/dark.svg b/zhi-admin-ui/src/assets/images/dark.svg new file mode 100644 index 0000000..f646bd7 --- /dev/null +++ b/zhi-admin-ui/src/assets/images/dark.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/images/light.svg b/zhi-admin-ui/src/assets/images/light.svg new file mode 100644 index 0000000..ab7cc08 --- /dev/null +++ b/zhi-admin-ui/src/assets/images/light.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/images/login-background.jpg b/zhi-admin-ui/src/assets/images/login-background.jpg new file mode 100644 index 0000000..333eb33 Binary files /dev/null and b/zhi-admin-ui/src/assets/images/login-background.jpg differ diff --git a/zhi-admin-ui/src/assets/images/profile.jpg b/zhi-admin-ui/src/assets/images/profile.jpg new file mode 100644 index 0000000..af2b032 Binary files /dev/null and b/zhi-admin-ui/src/assets/images/profile.jpg differ diff --git a/zhi-admin-ui/src/assets/js/china.js b/zhi-admin-ui/src/assets/js/china.js new file mode 100644 index 0000000..0a58c96 --- /dev/null +++ b/zhi-admin-ui/src/assets/js/china.js @@ -0,0 +1,792 @@ +/* eslint-disable no-undef */ +(function(root, factory) { + if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["exports", "echarts"], factory); + } else if ( + typeof exports === "object" && + typeof exports.nodeName !== "string" + ) { + // CommonJS + factory(exports, require("echarts")); + } else { + // Browser globals + factory({}, root.echarts); + } +})(this, function(exports, echarts) { + var log = function(msg) { + if (typeof console !== "undefined") { + console && console.error && console.error(msg); + } + }; + if (!echarts) { + log("ECharts is not Loaded"); + return; + } + if (!echarts.registerMap) { + log("ECharts Map is not loaded"); + return; + } + echarts.registerMap("china", { + type: "FeatureCollection", + features: [ + { + id: "710000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@°Ü¯Û"], + [ + "@@ƛĴÕƊÉɼģºðʀ\\ƎsÆNŌÔĚäœnÜƤɊĂǀĆĴžĤNJŨxĚĮǂƺòƌ‚–âÔ®ĮXŦţƸZûЋƕƑGđ¨ĭMó·ęcëƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ™¿@ăƑŽ¥ĘWǬÏĶŁâ" + ], + ["@@\\p|WoYG¿¥I†j@¢"], + ["@@…¡‰@ˆV^RqˆBbAŒnTXeRz¤Lž«³I"], + ["@@ÆEE—„kWqë @œ"], + ["@@fced"] + ], + encodeOffsets: [ + [[122886, 24033]], + [[123335, 22980]], + [[122375, 24193]], + [[122518, 24117]], + [[124427, 22618]], + [[124862, 26043]] + ] + }, + properties: { cp: [121.509062, 25.044332], name: "台湾", childNum: 6 } + }, + { + id: "130000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@o~†Z]‚ªr‰ºc_ħ²G¼s`jΟnüsœłNX_“M`ǽÓnUK…Ĝēs¤­©yrý§uģŒc†JŠ›e"], + ["@@U`Ts¿m‚"], + [ + "@@oºƋÄd–eVŽDJj£€J|Ådz•Ft~žKŨ¸IÆv|”‡¢r}膎onb˜}`RÎÄn°ÒdÞ²„^®’lnÐèĄlðӜ×]ªÆ}LiĂ±Ö`^°Ç¶p®đDcœŋ`–ZÔ’¶êqvFƚ†N®ĆTH®¦O’¾ŠIbÐã´BĐɢŴÆíȦp–ĐÞXR€·nndOž¤’OÀĈƒ­Qg˜µFo|gȒęSWb©osx|hYh•gŃfmÖĩnº€T̒Sp›¢dYĤ¶UĈjl’ǐpäìë|³kÛfw²Xjz~ÂqbTŠÑ„ěŨ@|oM‡’zv¢ZrÃVw¬ŧĖ¸fŒ°ÐT€ªqŽs{Sž¯r æÝlNd®²Ğ džiGʂJ™¼lr}~K¨ŸƐÌWö€™ÆŠzRš¤lêmĞL΄’@¡|q]SvK€ÑcwpÏρ†ĿćènĪWlĄkT}ˆJ”¤~ƒÈT„d„™pddʾĬŠ”ŽBVt„EÀ¢ôPĎƗè@~‚k–ü\\rÊĔÖæW_§¼F˜†´©òDòj’ˆYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkv‚GpuARhÞÆǶgʊTǼƹS£¨¡ù³ŘÍ]¿Ây™ôEP xX¶¹܇O¡“gÚ¡IwÃ鑦ÅB‡Ï|Ç°…N«úmH¯‹âŸDùŽyŜžŲIÄuШDž•¸dɂ‡‚FŸƒ•›Oh‡đ©OŸ›iÃ`ww^ƒÌkŸ‘ÑH«ƇǤŗĺtFu…{Z}Ö@U‡´…ʚLg®¯Oı°ÃwŸ ^˜—€VbÉs‡ˆmA…ê]]w„§›RRl£‡ȭµu¯b{ÍDěïÿȧŽuT£ġƒěŗƃĝ“Q¨fV†Ƌ•ƅn­a@‘³@šď„yýIĹÊKšŭfċŰóŒxV@tˆƯŒJ”]eƒR¾fe|rHA˜|h~Ėƍl§ÏŠlTíb ØoˆÅbbx³^zÃĶš¶Sj®A”yÂhðk`š«P€”ˈµEF†Û¬Y¨Ļrõqi¼‰Wi°§’б´°^[ˆÀ|ĠO@ÆxO\\tŽa\\tĕtû{ġŒȧXýĪÓjùÎRb›š^ΛfK[ݏděYfíÙTyŽuUSyŌŏů@Oi½’éŅ­aVcř§ax¹XŻác‡žWU£ôãºQ¨÷Ñws¥qEH‰Ù|‰›šYQoŕÇyáĂ£MðoťÊ‰P¡mšWO¡€v†{ôvîēÜISpÌhp¨ ‘j†deŔQÖj˜X³à™Ĉ[n`Yp@Už–cM`’RKhŒEbœ”pŞlNut®Etq‚nsÁŠgA‹iú‹oH‡qCX‡”hfgu“~ϋWP½¢G^}¯ÅīGCŸÑ^ãziMáļMTÃƘrMc|O_ž¯Ŏ´|‡morDkO\\mĆJfl@cĢ¬¢aĦtRıҙ¾ùƀ^juųœK­ƒUFy™—Ɲ…›īÛ÷ąV×qƥV¿aȉd³B›qPBm›aËđŻģm“Å®VŠ¹d^K‡KoŸnYg“¯Xhqa”Ldu¥•ÍpDž¡KąÅƒkĝęěhq‡}HyÓ]¹ǧ£…Í÷¿qᵧš™g‘¤o^á¾ZE‡¤i`ij{n•ƒOl»ŸWÝĔįhg›F[¿¡—ßkOüš_‰€ū‹i„DZàUtėGylƒ}ŒÓM}€jpEC~¡FtoQi‘šHkk{Ãmï‚" + ] + ], + encodeOffsets: [ + [[119712, 40641]], + [[121616, 39981]], + [[116462, 37237]] + ] + }, + properties: { cp: [114.502461, 38.045474], name: "河北", childNum: 3 } + }, + { + id: "140000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@Þĩ҃S‰ra}Á€yWix±Üe´lè“ßÓǏok‘ćiµVZģ¡coœ‘TS˹ĪmnÕńe–hZg{gtwªpXaĚThȑp{¶Eh—®RćƑP¿£‘Pmc¸mQÝW•ďȥoÅîɡųAďä³aωJ‘½¥PG­ąSM­™…EÅruµé€‘Yӎ•Ō_d›ĒCo­Èµ]¯_²ÕjāŽK~©ÅØ^ԛkïçămϑk]­±ƒcݯÑÃmQÍ~_a—pm…~ç¡q“ˆu{JÅŧ·Ls}–EyÁÆcI{¤IiCfUc•ƌÃp§]웫vD@¡SÀ‘µM‚ÅwuŽYY‡¡DbÑc¡hƒ×]nkoQdaMç~eD•ÛtT‰©±@¥ù@É¡‰ZcW|WqOJmĩl«ħşvOÓ«IqăV—¥ŸD[mI~Ó¢cehiÍ]Ɠ~ĥqXŠ·eƷœn±“}v•[ěďŽŕ]_‘œ•`‰¹ƒ§ÕōI™o©b­s^}Ét±ū«³p£ÿ·Wµ|¡¥ăFÏs׌¥ŅxŸÊdÒ{ºvĴÎêÌɊ²¶€ü¨|ÞƸµȲ‘LLúÉƎ¤ϊęĔV`„_bª‹S^|ŸdŠzY|dz¥p†ZbÆ£¶ÒK}tĦÔņƠ‚PYzn€ÍvX¶Ěn ĠÔ„zý¦ª˜÷žÑĸَUȌ¸‚dòÜJð´’ìúNM¬ŒXZ´‘¤ŊǸ_tldIš{¦ƀðĠȤ¥NehXnYG‚‡R° ƬDj¬¸|CĞ„Kq‚ºfƐiĺ©ª~ĆOQª ¤@ìǦɌ²æBŒÊ”TœŸ˜ʂōĖ’šĴŞ–ȀœÆÿȄlŤĒö„t”νî¼ĨXhŒ‘˜|ªM¤Ðz" + ], + encodeOffsets: [[116874, 41716]] + }, + properties: { cp: [112.549248, 37.857014], name: "山西", childNum: 1 } + }, + { + id: "150000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + [ + "@@Č^â£Ăh–šĖMÈÄw‚\\fŦ°W ¢¾luŸD„wŠ\\̀ʉÌÛM…Ā[bӞEn}¶Vc…ê“sƒ–›¯PqƒFB…‰|S•³C|kñ•H‹d‘iÄ¥sˆʼnő…PóÑÑE^‘ÅPpy_YtS™hQ·aHwsOnʼnÚs©iqj›‰€USiº]ïWš‰«gW¡A–R붛ijʕ…Œů`çõh]y»ǃŸǛҤxÒm~zf}pf|ÜroÈzrKÈĵSƧ„ż؜Ġu¦ö" + ], + [ + "@@sKCš…GS|úþX”gp›{ÁX¿Ÿć{ƱȏñZáĔyoÁhA™}ŅĆfdʼn„_¹„Y°ėǩÑ¡H¯¶oMQqð¡Ë™|‘Ñ`ƭŁX½·óۓxğįÅcQ‡ˆ“ƒs«tȋDžF“Ÿù^i‘t«Č¯[›hAi©á¥ÇĚ×l|¹y¯YȵƓ‹ñǙµï‚ċ™Ļ|Dœ™üȭ¶¡˜›oŽäÕG\\ďT¿Òõr¯œŸLguÏYęRƩšɷŌO\\İТæ^Ŋ IJȶȆbÜGŽĝ¬¿ĚVĎgª^íu½jÿĕęjık@Ľƒ]ėl¥Ë‡ĭûÁ„ƒėéV©±ćn©­ȇžÍq¯½•YÃÔʼn“ÉNѝÅÝy¹NqáʅDǡËñ­ƁYÅy̱os§ȋµʽǘǏƬɱà‘ưN¢ƔÊuľýľώȪƺɂļžxœZĈ}ÌʼnŪ˜ĺœŽĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~Ǎ›¼ȳÐUf†dIxÿ\\G ˆzâɏÙOº·pqy£†@ŒŠqþ@Ǟ˽IBäƣzsÂZ†ÁàĻdñ°ŕzéØűzșCìDȐĴĺf®ŽÀľưø@ɜÖÞKĊŇƄ§‚͑těï͡VAġÑÑ»d³öǍÝXĉĕÖ{þĉu¸ËʅğU̎éhɹƆ̗̮ȘNJ֥ड़ࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãüfƠSצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФԂ¤ƌžĞ̪Qʤ´¼mȠJˀŸƲÀɠmǐnǔĎȆÞǠN~€ʢĜ‚¶ƌĆĘźʆȬ˪ĚĒ¸ĞGȖƴƀj`ĢçĶāàŃºēĢƒĖćšYŒÀŎüôQÐÂŎŞdžŞêƖš˜oˆDĤÕºÑǘÛˤ³̀gńƘĔÀ^žªƂ`ªt¾äƚêĦĀ¼Ð€Ĕǎ¨Ȕ»͠^ˮÊȦƤøxRrŜH¤¸ÂxDĝŒ|ø˂˜ƮÐ¬ɚwɲFjĔ²Äw°dždÀɞ_ĸdîàŎjʜêTЪŌ‡ŜWÈ|tqĢUB~´°ÎFC•ŽU¼pĀēƄN¦¾O¶ŠłKĊOj“Ě”j´ĜYp˜{¦„ˆSĚÍ\\Tš×ªV–÷Ší¨ÅDK°ßtŇĔKš¨ǵÂcḷ̌ĚǣȄĽF‡lġUĵœŇ‹ȣFʉɁƒMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFŽxúQ„Er´W„rh¤Ɛ \\talĈDJ˜Ü|[Pll̚¸ƎGú´Pž¬W¦†^¦–H]prR“n|or¾wLVnÇIujkmon£cX^Bh`¥V”„¦U¤¸}€xRj–[^xN[~ªŠxQ„‚[`ªHÆÂExx^wšN¶Ê˜|¨ì†˜€MrœdYp‚oRzNy˜ÀDs~€bcfÌ`L–¾n‹|¾T‚°c¨È¢a‚r¤–`[|òDŞĔöxElÖdH„ÀI`„Ď\\Àì~ƎR¼tf•¦^¢ķ¶e”ÐÚMŒptgj–„ɡČÅyġLû™ŇV®ŠÄÈƀ†Ď°P|ªVV†ªj–¬ĚÒêp¬–E|ŬÂc|ÀtƐK fˆ{ĘFĒœƌXƲąo½Ę‘\\¥–o}›Ûu£ç­kX‘{uĩ«āíÓUŅßŢq€Ť¥lyň[€oi{¦‹L‡ń‡ðFȪȖ”ĒL„¿Ì‹ˆfŒ£K£ʺ™oqNŸƒwğc`ue—tOj×°KJ±qƒÆġm‰Ěŗos¬…qehqsuœƒH{¸kH¡Š…ÊRǪÇƌbȆ¢´ä܍¢NìÉʖ¦â©Ż؛Ç@Vu»A—ylßí¹ĵê…ÝlISò³C¹Ìâ„²i¶’Ìoú^H“²CǜңDŽ z¼g^èöŰ_‹‚–†IJĕꄜ}gÁnUI«m‰…„‹]j‡vV¼euhwqA„aW˜ƒ_µj…»çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáG“›OUۗOB±•XŸkŇ¹£k|e]ol™ŸkVͼÕqtaÏõjgÁ£§U^Œ”RLˆËnX°Ç’Bz†^~wfvˆypV ¯„ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖM×ÍEyx‹þp]Évïè‘vƀnÂĴÖ@‚‰†V~Ĉ™Š³MEˆĸÅĖt—ējyÄDXÄxGQuv_›i¦aBçw‘˛wD™©{ŸtāmQ€{EJ§KPśƘƿ¥@‰sCT•É}ɃwˆƇy±ŸgÑ“}T[÷kÐ禫…SÒ¥¸ëBX½‰HáŵÀğtSÝÂa[ƣ°¯¦P]£ġ“–“Òk®G²„èQ°óMq}EŠóƐÇ\\ƒ‡@áügQ͋u¥Fƒ“T՛¿Jû‡]|mvāÎYua^WoÀa·­ząÒot׶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶—ˆ¿A•†‹[¡Œ{d×uQAƒ›M•xV‹vMOmăl«ct[wº_šÇʊŽŸjb£ĦS_é“QZ“_lwgOiýe`YYLq§IÁˆdz£ÙË[ÕªuƏ³ÍT—s·bÁĽäė[›b[ˆŗfãcn¥îC¿÷µ[ŏÀQ­ōšĉm¿Á^£mJVm‡—L[{Ï_£›F¥Ö{ŹA}…×Wu©ÅaųijƳhB{·TQqÙIķˑZđ©Yc|M¡…L•eVUóK_QWk’_ĥ‘¿ãZ•»X\\ĴuUƒè‡lG®ěłTĠğDєOrÍd‚ÆÍz]‹±…ŭ©ŸÅ’]ŒÅÐ}UË¥©Tċ™ïxgckfWgi\\ÏĒ¥HkµE˜ë{»ÏetcG±ahUiñiWsɁˆ·c–C‚Õk]wȑ|ća}w…VaĚ᠞ŒG°ùnM¬¯†{ȈÐÆA’¥ÄêJxÙ¢”hP¢Ûˆº€µwWOŸóFŽšÁz^ÀŗÎú´§¢T¤ǻƺSė‰ǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇq‡Z‘ñiñC³ª—…»E`¨åXēÕqÉû[l•}ç@čƘóO¿¡ƒFUsA‰“ʽīccšocƒ‚ƒÇS}„“£‡IS~ălkĩXçmĈ…ŀЂoÐdxÒuL^T{r@¢‘žÍƒĝKén£kQ™‰yšÅõËXŷƏL§~}kqš»IHėDžjĝŸ»ÑÞoŸå°qTt|r©ÏS‹¯·eŨĕx«È[eMˆ¿yuˆ‘pN~¹ÏyN£{©’—g‹ħWí»Í¾s“əšDž_ÃĀɗ±ą™ijĉʍŌŷ—S›É“A‹±åǥɋ@럣R©ąP©}ĹªƏj¹erƒLDĝ·{i«ƫC£µ" + ] + ], + encodeOffsets: [[[127444, 52594]], [[113793, 40312]]] + }, + properties: { cp: [111.670801, 40.818311], name: "内蒙古", childNum: 2 } + }, + { + id: "210000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@L–Ž@@s™a"], + ["@@MnNm"], + ["@@d‚c"], + ["@@eÀ‚C@b‚“‰"], + ["@@f‡…Xwkbr–Ä`qg"], + ["@@^jtW‘Q"], + ["@@~ Y]c"], + ["@@G`ĔN^_¿Z‚ÃM"], + ["@@iX¶B‹Y"], + ["@@„YƒZ"], + ["@@L_{Epf"], + ["@@^WqCT\\"], + ["@@\\[“‹§t|”¤_"], + ["@@m`n_"], + ["@@Ïxnj{q_×^Giip"], + [ + "@@@œé^B†‡ntˆaÊU—˜Ÿ]x ¯ÄPIJ­°h€ʙK³†VˆÕ@Y~†|EvĹsDŽ¦­L^p²ŸÒG ’Ël]„xxÄ_˜fT¤Ď¤cŽœP„–C¨¸TVjbgH²sdÎdHt`Bˆ—²¬GJję¶[ÐhjeXdlwhšðSȦªVÊπ‹Æ‘Z˜ÆŶ®²†^ŒÎyÅÎcPqń“ĚDMħĜŁH­ˆk„çvV[ij¼W–‚YÀäĦ’‘`XlžR`žôLUVžfK–¢†{NZdĒª’YĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~†źBŽ|¦ÕœEž¤Ð`\\|Kˆ˜UnnI]¤ÀÂĊnŎ™R®Ő¿¶\\ÀøíDm¦ÎbŨab‰œaĘ\\ľã‚¸a˜tÎSƐ´©v\\ÖÚÌǴ¤Â‡¨JKr€Z_Z€fjþhPkx€`Y”’RIŒjJcVf~sCN¤ ˆE‚œhæm‰–sHy¨SðÑÌ\\\\ŸĐRZk°IS§fqŒßýáЍÙÉÖ[^¯ǤŲ„ê´\\¦¬ĆPM¯£Ÿˆ»uïpùzEx€žanµyoluqe¦W^£ÊL}ñrkqWňûP™‰UP¡ôJŠoo·ŒU}£Œ„[·¨@XŒĸŸ“‹‹DXm­Ûݏº‡›GU‹CÁª½{íĂ^cj‡k“¶Ã[q¤“LÉö³cux«zZfƒ²BWÇ®Yß½ve±ÃC•ý£W{Ú^’q^sÑ·¨‹ÍOt“¹·C¥‡GD›rí@wÕKţ݋˜Ÿ«V·i}xËÍ÷‘i©ĝ‡ɝǡ]ƒˆ{c™±OW‹³Ya±Ÿ‰_穂Hžĕoƫ€Ňqƒr³‰Lys[„ñ³¯OS–ďOMisZ†±ÅFC¥Pq{‚Ã[Pg}\\—¿ghćO…•k^ģÁFıĉĥM­oEqqZûěʼn³F‘¦oĵ—hŸÕP{¯~TÍlª‰N‰ßY“Ð{Ps{ÃVU™™eĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀff‘dF~ˆ€ĀeĖ€d`sx² šƒ®EżĀdQ‹Âd^~ăÔHˆ¦\\›LKpĄVez¤NP ǹӗR™ÆąJSh­a[¦´Âghwm€BÐ¨źhI|žVVŽ—Ž|p] Â¼èNä¶ÜBÖ¼“L`‚¼bØæŒKV”ŸpoœúNZÞÒKxpw|ÊEMnzEQšŽIZ”ŽZ‡NBˆčÚFÜçmĩ‚WĪñt‘ÞĵÇñZ«uD‚±|Əlij¥ãn·±PmÍa‰–da‡ CL‡Ǒkùó¡³Ï«QaċϑOÃ¥ÕđQȥċƭy‹³ÃA" + ] + ], + encodeOffsets: [ + [[123686, 41445]], + [[126019, 40435]], + [[124393, 40128]], + [[126117, 39963]], + [[125322, 40140]], + [[126686, 40700]], + [[126041, 40374]], + [[125584, 40168]], + [[125453, 40165]], + [[125362, 40214]], + [[125280, 40291]], + [[125774, 39997]], + [[125976, 40496]], + [[125822, 39993]], + [[125509, 40217]], + [[122731, 40949]] + ] + }, + properties: { cp: [123.429096, 41.796767], name: "辽宁", childNum: 16 } + }, + { + id: "220000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@‘p䔳PClƒFbbÍzš€wBG’ĭ€Z„Åi“»ƒlY­ċ²SgŽkÇ£—^S‰“qd¯•‹R…©éŽ£¯S†\\cZ¹iűƏCuƍÓX‡oR}“M^o•£…R}oªU­F…uuXHlEŕ‡€Ï©¤ÛmTŽþ¤D–²ÄufàÀ­XXȱAe„yYw¬dvõ´KÊ£”\\rµÄl”iˆdā]|DÂVŒœH¹ˆÞ®ÜWnŒC”Œķ W‹§@\\¸‹ƒ~¤‹Vp¸‰póIO¢ŠVOšŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúvð‡¼¤ N°ąO¥«³[ƒéǡű_°Õ\\ÚÊĝŽþâőàerR¨­JYlďQ[ ÏYëЧTGz•tnŠß¡gFkMŸāGÁ¤ia É‰™È¹`\\xs€¬dĆkNnuNUŠ–užP@‚vRY¾•–\\¢…ŒGªóĄ~RãÖÎĢù‚đŴÕhQŽxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp‚]vbÍZuĂ{nˆ^IüœÀSք”¦EŒvRÎûh@℈[‚Əȉô~FNr¯ôçR±ƒ­HÑl•’Ģ–^¤¢‚OðŸŒævxsŒ]ÞÁTĠs¶¿âƊGW¾ìA¦·TѬ†è¥€ÏÐJ¨¼ÒÖ¼ƒƦɄxÊ~S–tD@ŠĂ¼Ŵ¡jlºWžvЉˆzƦZЎ²CH— „Axiukd‹ŒGgetqmcžÛ£Ozy¥cE}|…¾cZ…k‚‰¿uŐã[oxGikfeäT@…šSUwpiÚFM©’£è^ڟ‚`@v¶eň†f h˜eP¶žt“äOlÔUgƒÞzŸU`lœ}ÔÆUvØ_Ō¬Öi^ĉi§²ÃŠB~¡Ĉ™ÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYx‘ƘDVÇĺĿg¿cwÅ\\¹˜¥Yĭlœ¤žOv†šLjM_a W`zļMž·\\swqÝSA‡š—q‰Śij¯Š‘°kŠRē°wx^Đkǂғ„œž“œŽ„‹\\]˜nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°“G³¼XÀ““™¤¹i´o¤ŃšŸÈ`̃DzÄUĞd\\i֚ŒˆmÈBĤÜɲDEh LG¾ƀľ{WaŒYÍȏĢĘÔRîĐj‹}Ǟ“ccj‡oUb½š{“h§Ǿ{K‹ƖµÎ÷žGĀÖŠåưÎs­l›•yiē«‹`姝H¥Ae^§„GK}iã\\c]v©ģZ“mÃ|“[M}ģTɟĵ‘Â`À–çm‰‘FK¥ÚíÁbXš³ÌQґHof{‰]e€pt·GŋĜYünĎųVY^’˜ydõkÅZW„«WUa~U·Sb•wGçǑ‚“iW^q‹F‚“›uNĝ—·Ew„‹UtW·Ýďæ©PuqEzwAV•—XR‰ãQ`­©GŒM‡ehc›c”ďϝd‡©ÑW_ϗYƅŒ»…é\\ƒɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ý‘L¡‘ýŸqT^rme™\\Pp•ZZbƒyŸ’uybQ—efµ]UhĿDCmûvašÙNSkCwn‰cćfv~…Y‹„ÇG" + ], + encodeOffsets: [[130196, 42528]] + }, + properties: { cp: [125.3245, 43.886841], name: "吉林", childNum: 1 } + }, + { + id: "230000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@ƨƒĶTLÇyqpÇÛqe{~oyen}s‰`q‡iXG”ù]Ëp½“©lɇÁp]Þñ´FÔ^f‘äîºkà˜z¼BUvÈ@"], + [ + "@@UƒµNÿ¥īè灋•HÍøƕ¶LŒǽ|g¨|”™Ža¾pViˆdd”~ÈiŒíďÓQġėǐZ΋ŽXb½|ſÃH½ŸKFgɱCģÛÇA‡n™‹jÕc[VĝDZÃ˄Ç_™ £ń³pŽj£º”š¿”»WH´¯”U¸đĢmžtĜyzzNN|g¸÷äűѱĉā~mq^—Œ[ƒ”››”ƒǁÑďlw]¯xQĔ‰¯l‰’€°řĴrŠ™˜BˆÞTxr[tŽ¸ĻN_yŸX`biN™Ku…P›£k‚ZĮ—¦[ºxÆÀdhŽĹŀUÈƗCw’áZħÄŭcÓ¥»NAw±qȥnD`{ChdÙFćš}¢‰A±Äj¨]ĊÕjŋ«×`VuÓś~_kŷVÝyh„“VkÄãPs”Oµ—fŸge‚Ň…µf@u_Ù ÙcŸªNªÙEojVx™T@†ãSefjlwH\\pŏäÀvŠŽlY†½d{†F~¦dyz¤PÜndsrhf‹HcŒvlwjFœ£G˜±DύƥY‡yϊu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|Cš˜zxAè¥bœfudTrFWÁ¹Am|˜ĔĕsķÆF‡´Nš‰}ć…UŠÕ@Áijſmužç’uð^ÊýowŒFzØÎĕNőžǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°ƒUŸzou‡xe]}Ž…AyȑW¯ÌmK‡“Q]‹Īºif¸ÄX|sZt|½ÚUΠlkš^p{f¤lˆºlÆW –€A²˜PVܜPH”Êâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi†`¶—„bXƒrBgxfv»ŽuUiˆŒ^v~”J¬mVp´£Œ´VWrnP½ì¢BX‚¬h™ŠðX¹^TjVœŠriªj™tŊÄm€tPGx¸bgRšŽsT`ZozÆO]’ÒFô҆Oƒ‡ŊŒvŞ”p’cGŒêŠsx´DR–Œ{A†„EOr°Œ•žx|íœbˆ³Wm~DVjºéNN†Ëܲɶ­GƒxŷCStŸ}]ûō•SmtuÇÃĕN•™āg»šíT«u}ç½BĵÞʣ¥ëÊ¡Mێ³ãȅ¡ƋaǩÈÉQ‰†G¢·lG|›„tvgrrf«†ptęŘnŠÅĢr„I²¯LiØsPf˜_vĠd„xM prʹšL¤‹¤‡eˌƒÀđK“žïÙVY§]I‡óáĥ]ķ†Kˆ¥Œj|pŇ\\kzţ¦šnņäÔVĂîĪ¬|vW’®l¤èØr‚˜•xm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄ–Ą»ƢjȦOǺ¨ìSŖÆƬy”Qœv`–cwƒZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨS’Œfm Ċ‚ƀP̎ēz©Ċ‚ÄÕÊmgŸÇsJ¥ƔˆŊśæ’΁Ñqv¿íUOµª‰ÂnĦÁ_½ä@ê텣P}Ġ[@gġ}g“ɊדûÏWXá¢užƻÌsNͽƎÁ§č՛AēeL³àydl›¦ĘVçŁpśdžĽĺſʃQíÜçÛġԏsĕ¬—Ǹ¯YßċġHµ ¡eå`ļƒrĉŘóƢFì“ĎWøxÊk†”ƈdƬv|–I|·©NqńRŀƒ¤é”eŊœŀ›ˆàŀU²ŕƀB‚Q£Ď}L¹Îk@©ĈuǰųǨ”Ú§ƈnTËÇéƟÊcfčŤ^Xm‡—HĊĕË«W·ċëx³ǔķÐċJā‚wİ_ĸ˜Ȁ^ôWr­°oú¬Ħ…ŨK~”ȰCĐ´Ƕ£’fNÎèâw¢XnŮeÂÆĶŽ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®‚ØCÔ ŬGƠ”ƦYĜ‡ĘÜƬDJ—g_ͥœ@čŅĻA“¶¯@wÎqC½Ĉ»NŸăëK™ďÍQ“Ùƫ[«Ãí•gßÔÇOÝáW‘ñuZ“¯ĥ€Ÿŕā¡ÑķJu¤E Ÿå¯°WKɱ_d_}}vyŸõu¬ï¹ÓU±½@gÏ¿rýD‰†g…Cd‰µ—°MFYxw¿CG£‹Rƛ½Õ{]L§{qqąš¿BÇƻğëšܭNJË|c²}Fµ}›ÙRsÓpg±ŠQNqǫŋRwŕnéÑÉKŸ†«SeYR…ŋ‹@{¤SJ}šD Ûǖ֍Ÿ]gr¡µŷjqWÛham³~S«“„›Þ]" + ] + ], + encodeOffsets: [[[127123, 51780]], [[134456, 44547]]] + }, + properties: { cp: [126.642464, 45.756967], name: "黑龙江", childNum: 2 } + }, + { + id: "320000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@cþÅPiŠ`ZŸRu¥É\\]~°ŽY`µ†Óƒ^phÁbnÀşúŽòa–ĬºTÖŒb‚˜e¦¦€{¸ZâćNpŒ©žHr|^ˆmjhŠSEb\\afv`sz^lkŽlj‹Ätg‹¤D˜­¾Xš¿À’|ДiZ„ȀåB·î}GL¢õcßjaŸyBFµÏC^ĭ•cÙt¿sğH]j{s©HM¢ƒQnDÀ©DaÜތ·jgàiDbPufjDk`dPOîƒhw¡ĥ‡¥šG˜ŸP²ĐobºrY†„î¶aHŢ´ ]´‚rılw³r_{£DB_Ûdåuk|ˆŨ¯F Cºyr{XFy™e³Þċ‡¿Â™kĭB¿„MvÛpm`rÚã”@Ę¹hågËÖƿxnlč¶Åì½Ot¾dJlŠVJʜǀœŞqvnOŠ^ŸJ”Z‘ż·Q}ê͎ÅmµÒ]Žƍ¦Dq}¬R^èĂ´ŀĻĊIԒtžIJyQŐĠMNtœR®òLh‰›Ěs©»œ}OӌGZz¶A\\jĨFˆäOĤ˜HYš†JvÞHNiÜaϚɖnFQlšNM¤ˆB´ĄNöɂtp–Ŭdf先‹qm¿QûŠùއÚb¤uŃJŴu»¹Ą•lȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Y™xci‡tğ®jű¢KOķ•Coy`å®VTa­_Ā]ŐÝɞï²ʯÊ^]afYǸÃĆēĪȣJđ͍ôƋĝÄ͎ī‰çÛɈǥ£­ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ—¡RLčiXy‡ÅNïă¡¸iĔϑNÌŕoēdōîåŤûHcs}~Ûwbù¹£¦ÓCt‹OPrƒE^ÒoŠg™ĉIµžÛÅʹK…¤½phMŠü`o怆ŀ" + ], + encodeOffsets: [[121740, 32276]] + }, + properties: { cp: [118.767413, 32.041544], name: "江苏", childNum: 1 } + }, + { + id: "330000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@E^dQ]K"], + ["@@jX^j‡"], + ["@@sfŠbU‡"], + ["@@qP\\xz[ck"], + ["@@‘Rƒ¢‚FX}°[s_"], + ["@@Cbœ\\—}"], + ["@@e|v\\la{u"], + ["@@v~u}"], + ["@@QxÂF¯}"], + ["@@¹nŒvÞs¯o"], + ["@@rSkUEj"], + ["@@bi­ZŒP"], + ["@@p[}INf"], + ["@@À¿€"], + ["@@¹dnbŒ…"], + ["@@rSŸBnR"], + ["@@g~h}"], + ["@@FlEk"], + ["@@OdPc"], + ["@@v[u\\"], + ["@@FjâL~wyoo~›sµL–\\"], + ["@@¬e¹aNˆ"], + ["@@\\nÔ¡q]L³ë\\ÿ®ŒQ֎"], + ["@@ÊA­©[¬"], + ["@@KxŒv­"], + ["@@@hlIk]"], + ["@@pW{o||j"], + ["@@Md|_mC"], + ["@@¢…X£ÏylD¼XˆtH"], + ["@@hlÜ[LykAvyfw^Ež›¤"], + ["@@fp¤Mus“R"], + ["@@®_ma~•LÁ¬šZ"], + ["@@iM„xZ"], + ["@@ZcYd"], + ["@@Z~dOSo|A¿qZv"], + ["@@@`”EN¡v"], + ["@@|–TY{"], + ["@@@n@m"], + ["@@XWkCT\\"], + ["@@ºwšZRkĕWO¢"], + ["@@™X®±Grƪ\\ÔáXq{‹"], + ["@@ůTG°ĄLHm°UC‹"], + [ + "@@¤Ž€aÜx~}dtüGæţŎíĔcŖpMËВjē¢·ðĄÆMzˆjWKĎ¢Q¶˜À_꒔_Bı€i«pZ€gf€¤Nrq]§ĂN®«H±‡yƳí¾×ŸīàLłčŴǝĂíÀBŖÕªˆŠÁŖHŗʼnåqûõi¨hÜ·ƒñt»¹ýv_[«¸m‰YL¯‰Qª…mĉÅdMˆ•gÇjcº«•ęœ¬­K­´ƒB«Âącoċ\\xKd¡gěŧ«®á’[~ıxu·Å”KsËɏc¢Ù\\ĭƛëbf¹­ģSƒĜkáƉÔ­ĈZB{ŠaM‘µ‰fzʼnfåÂŧįƋǝÊĕġć£g³ne­ą»@­¦S®‚\\ßðCšh™iqªĭiAu‡A­µ”_W¥ƣO\\lċĢttC¨£t`ˆ™PZäuXßBs‡Ļyek€OđġĵHuXBšµ]׌‡­­\\›°®¬F¢¾pµ¼kŘó¬Wät’¸|@ž•L¨¸µr“ºù³Ù~§WI‹ŸZWŽ®’±Ð¨ÒÉx€`‰²pĜ•rOògtÁZ}þÙ]„’¡ŒŸFK‚wsPlU[}¦Rvn`hq¬\\”nQ´ĘRWb”‚_ rtČFI֊kŠŠĦPJ¶ÖÀÖJĈĄTĚòžC ²@Pú…Øzœ©PœCÈڜĒ±„hŖ‡l¬â~nm¨f©–iļ«m‡nt–u†ÖZÜÄj“ŠLŽ®E̜Fª²iÊxبžIÈhhst" + ], + ["@@o\\V’zRZ}y"], + ["@@†@°¡mۛGĕ¨§Ianá[ýƤjfæ‡ØL–•äGr™"] + ], + encodeOffsets: [ + [[125592, 31553]], + [[125785, 31436]], + [[125729, 31431]], + [[125513, 31380]], + [[125223, 30438]], + [[125115, 30114]], + [[124815, 29155]], + [[124419, 28746]], + [[124095, 28635]], + [[124005, 28609]], + [[125000, 30713]], + [[125111, 30698]], + [[125078, 30682]], + [[125150, 30684]], + [[124014, 28103]], + [[125008, 31331]], + [[125411, 31468]], + [[125329, 31479]], + [[125626, 30916]], + [[125417, 30956]], + [[125254, 30976]], + [[125199, 30997]], + [[125095, 31058]], + [[125083, 30915]], + [[124885, 31015]], + [[125218, 30798]], + [[124867, 30838]], + [[124755, 30788]], + [[124802, 30809]], + [[125267, 30657]], + [[125218, 30578]], + [[125200, 30562]], + [[124968, 30474]], + [[125167, 30396]], + [[124955, 29879]], + [[124714, 29781]], + [[124762, 29462]], + [[124325, 28754]], + [[123990, 28459]], + [[125366, 31477]], + [[125115, 30363]], + [[125369, 31139]], + [[122495, 31878]], + [[125329, 30690]], + [[125192, 30787]] + ] + }, + properties: { cp: [120.153576, 30.287459], name: "浙江", childNum: 45 } + }, + { + id: "340000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@^iuLX^"], + ["@@‚e©Ehl"], + [ + "@@°ZÆëϵmkǀwÌÕæhºgBĝâqÙĊz›ÖgņtÀÁÊÆá’hEz|WzqD¹€Ÿ°E‡ŧl{ævÜcA`¤C`|´qžxIJkq^³³ŸGšµbƒíZ…¹qpa±ď OH—¦™Ħˆx¢„gPícOl_iCveaOjCh߸i݋bÛªCC¿€m„RV§¢A|t^iĠGÀtÚs–d]ĮÐDE¶zAb àiödK¡~H¸íæAžǿYƒ“j{ď¿‘™À½W—®£ChŒÃsiŒkkly]_teu[bFa‰Tig‡n{]Gqªo‹ĈMYá|·¥f¥—őaSÕė™NµñĞ«ImŒ_m¿Âa]uĜp …Z_§{Cƒäg¤°r[_Yj‰ÆOdý“[ŽI[á·¥“Q_n‡ùgL¾mv™ˊBÜƶĊJhšp“c¹˜O]iŠ]œ¥ jtsggJǧw×jÉ©±›EFˍ­‰Ki”ÛÃÕYv…s•ˆm¬njĻª•§emná}k«ŕˆƒgđ²Ù›DǤ›í¡ªOy›†×Où±@DŸñSęćăÕIÕ¿IµĥO‰‰jNÕËT¡¿tNæŇàåyķrĕq§ÄĩsWÆߎF¶žX®¿‰mŒ™w…RIޓfßoG‘³¾©uyH‘į{Ɓħ¯AFnuP…ÍÔzšŒV—dàôº^Ðæd´€‡oG¤{S‰¬ćxã}›ŧ×Kǥĩ«žÕOEзÖdÖsƘѨ[’Û^Xr¢¼˜§xvěƵ`K”§ tÒ´Cvlo¸fzŨð¾NY´ı~ÉĔē…ßúLÃϖ_ÈÏ|]ÂÏFl”g`bšežž€n¾¢pU‚h~ƴĖ¶_‚r sĄ~cž”ƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³…]’u}›f…ïQl{skl“oNdŸjŸäËzDvčoQŠďHI¦rb“tHĔ~BmlRš—V_„ħTLnñH±’DžœL‘¼L˜ªl§Ťa¸ŒĚlK²€\\RòvDcÎJbt[¤€D@®hh~kt°ǾzÖ@¾ªdb„YhüóZ ň¶vHrľ\\ʗJuxAT|dmÀO„‹[ÃԋG·ĚąĐlŪÚpSJ¨ĸˆLvÞcPæķŨŽ®mАˆálŸwKhïgA¢ųƩޖ¤OȜm’°ŒK´" + ] + ], + encodeOffsets: [ + [[121722, 32278]], + [[119475, 30423]], + [[119168, 35472]] + ] + }, + properties: { cp: [117.283042, 31.86119], name: "安徽", childNum: 3 } + }, + { + id: "350000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@“zht´‡]"], + ["@@aj^~ĆG—©O"], + ["@@ed¨„C}}i"], + ["@@@vˆPGsQ"], + ["@@‰sBz‚ddW]Q"], + ["@@SŽ¨Q“{"], + ["@@NŽVucW"], + ["@@qptBAq"], + ["@@‰’¸[mu"], + ["@@Q\\pD]_"], + ["@@jSwUadpF"], + ["@@eXª~ƒ•"], + ["@@AjvFso"], + ["@@fT–›_Çí\\Ÿ™—v|ba¦jZÆy€°"], + ["@@IjJi"], + ["@@wJI€ˆxš«¼AoNe{M­"], + ["@@K‰±¡Óˆ”ČäeZ"], + [ + "@@k¡¹Eh~c®wBk‹UplÀ¡I•~Māe£bN¨gZý¡a±Öcp©PhžI”Ÿ¢Qq…ÇGj‹|¥U™ g[Ky¬ŏ–v@OpˆtÉEŸF„\\@ åA¬ˆV{Xģ‰ĐBy…cpě…¼³Ăp·¤ƒ¥o“hqqÚ¡ŅLsƒ^ᗞ§qlŸÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ß–ėu›ĕeûҍiÁŧSW¥˜QŠûŗ½ùěcݧSùĩąSWó«íęACµ›eR—åǃRCÒÇZÍ¢‹ź±^dlsŒtjD¸•‚ZpužÔâÒH¾oLUêÃÔjjēò´ĄW‚ƛ…^Ñ¥‹ĦŸ@Çò–ŠmŒƒOw¡õyJ†yD}¢ďÑÈġfŠZd–a©º²z£šN–ƒjD°Ötj¶¬ZSÎ~¾c°¶Ðm˜x‚O¸¢Pl´žSL|¥žA†ȪĖM’ņIJg®áIJČĒü` ŽQF‡¬h|ÓJ@zµ |ê³È ¸UÖŬŬÀEttĸr‚]€˜ðŽM¤ĶIJHtÏ A’†žĬkvsq‡^aÎbvŒd–™fÊòSD€´Z^’xPsÞrv‹ƞŀ˜jJd×ŘÉ ®A–ΦĤd€xĆqAŒ†ZR”ÀMźŒnĊ»ŒİÐZ— YX–æJŠyĊ²ˆ·¶q§·–K@·{s‘Xãô«lŗ¶»o½E¡­«¢±¨Yˆ®Ø‹¶^A™vWĶGĒĢžPlzfˆļŽtàAvWYãšO_‡¤sD§ssČġ[kƤPX¦Ž`¶“ž®ˆBBvĪjv©šjx[L¥àï[F…¼ÍË»ğV`«•Ip™}ccÅĥZE‹ãoP…´B@ŠD—¸m±“z«Ƴ—¿å³BRضˆœWlâþäą`“]Z£Tc— ĹGµ¶H™m@_©—kŒ‰¾xĨ‡ôȉðX«½đCIbćqK³Á‹Äš¬OAwã»aLʼn‡ËĥW[“ÂGI—ÂNxij¤D¢ŽîĎÎB§°_JœGsƒ¥E@…¤uć…P‘å†cuMuw¢BI¿‡]zG¹guĮck\\_" + ] + ], + encodeOffsets: [ + [[123250, 27563]], + [[122541, 27268]], + [[123020, 27189]], + [[122916, 27125]], + [[122887, 26845]], + [[122808, 26762]], + [[122568, 25912]], + [[122778, 26197]], + [[122515, 26757]], + [[122816, 26587]], + [[123388, 27005]], + [[122450, 26243]], + [[122578, 25962]], + [[121255, 25103]], + [[120987, 24903]], + [[122339, 25802]], + [[121042, 25093]], + [[122439, 26024]] + ] + }, + properties: { cp: [119.306239, 26.075302], name: "福建", childNum: 18 } + }, + { + id: "360000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@ĢĨƐgļˆ¼ÂMD~ņªe^\\^§„ý©j׍cZ†Ø¨zdÒa¶ˆlҍJŒìõ`oz÷@¤u޸´†ôęöY¼‰HČƶajlÞƩ¥éZ[”|h}^U Œ ¥p„ĄžƦO lt¸Æ €Q\\€ŠaÆ|CnÂOjt­ĚĤd’ÈŒF`’¶„@Ð딠¦ōҞ¨Sêv†HĢûXD®…QgėWiØPÞìºr¤dž€NĠ¢l–•ĄtZoœCƞÔºCxrpĠV®Ê{f_Y`_ƒeq’’®Aot`@o‚DXfkp¨|Šs¬\\D‘ÄSfè©Hn¬…^DhÆyøJh“ØxĢĀLʈ„ƠPżċĄwȠ̦G®ǒĤäTŠÆ~ĦwŠ«|TF¡Šn€c³Ïå¹]ĉđxe{ÎӐ†vOEm°BƂĨİ|G’vz½ª´€H’àp”eJ݆Qšxn‹ÀŠW­žEµàXÅĪt¨ÃĖrÄwÀFÎ|ňÓMå¼ibµ¯»åDT±m[“r«_gŽmQu~¥V\\OkxtL E¢‹ƒ‘Ú^~ýê‹Pó–qo슱_Êw§ÑªåƗā¼‹mĉŹ‹¿NQ“…YB‹ąrwģcÍ¥B•Ÿ­ŗÊcØiI—žƝĿuŒqtāwO]‘³YCñTeɕš‹caub͈]trlu€ī…B‘ПGsĵıN£ï—^ķqss¿FūūV՟·´Ç{éĈý‰ÿ›OEˆR_ŸđûIċâJh­ŅıN‘ȩĕB…¦K{Tk³¡OP·wn—µÏd¯}½TÍ«YiµÕsC¯„iM•¤™­•¦¯P|ÿUHv“he¥oFTu‰õ\\ŽOSs‹MòđƇiaºćXŸĊĵà·çhƃ÷ǜ{‘ígu^›đg’m[×zkKN‘¶Õ»lčÓ{XSƉv©_ÈëJbVk„ĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B„±’ÌŒK˜y’áV‡¼Ã~­…`g›ŸsÙfI›Ƌlę¹e|–~udjˆuTlXµf`¿JdŠ[\\˜„L‚‘²" + ], + encodeOffsets: [[116689, 26234]] + }, + properties: { cp: [115.892151, 28.676493], name: "江西", childNum: 1 } + }, + { + id: "370000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@Xjd]{K"], + ["@@itbFHy"], + ["@@HlGk"], + ["@@T‚ŒGŸy"], + ["@@K¬˜•‹U"], + ["@@WdXc"], + ["@@PtOs"], + ["@@•LnXhc"], + ["@@ppVƒu]Or"], + ["@@cdzAUa"], + ["@@udRhnCI‡"], + ["@@ˆoIƒpR„"], + [ + "@@Ľč{fzƤî’Kš–ÎMĮ]†—ZFˆ½Y]â£ph’™š¶¨râøÀ†ÎǨ¤^ºÄ”Gzˆ~grĚĜlĞƄLĆdž¢Îo¦–cv“Kb€gr°Wh”mZp ˆL]LºcU‰Æ­n”żĤÌĒœbAnrOAœ´žȊcÀbƦUØrĆUÜøœĬƞ†š˜Ez„VL®öØBkŖÝĐĖ¹ŧ̄±ÀbÎɜnb²ĦhņBĖ›žįĦåXćì@L¯´ywƕCéõė ƿ¸‘lµ¾Z|†ZWyFYŸ¨Mf~C¿`€à_RÇzwƌfQnny´INoƬˆèôº|sT„JUš›‚L„îVj„ǎ¾Ē؍‚Dz²XPn±ŴPè¸ŔLƔÜƺ_T‘üÃĤBBċȉöA´fa„˜M¨{«M`‡¶d¡ô‰Ö°šmȰBÔjjŒ´PM|”c^d¤u•ƒ¤Û´Œä«ƢfPk¶Môlˆ]Lb„}su^ke{lC‘…M•rDŠÇ­]NÑFsmoõľH‰yGă{{çrnÓE‰‹ƕZGª¹Fj¢ïW…uøCǷ돡ąuhÛ¡^Kx•C`C\\bÅxì²ĝÝ¿_N‰īCȽĿåB¥¢·IŖÕy\\‡¹kx‡Ã£Č×GDyÕ¤ÁçFQ¡„KtŵƋ]CgÏAùSed‡cÚź—ŠuYfƒyMmhUWpSyGwMPqŀ—›Á¼zK›¶†G•­Y§Ëƒ@–´śÇµƕBmœ@Io‚g——Z¯u‹TMx}C‘‰VK‚ï{éƵP—™_K«™pÛÙqċtkkù]gŽ‹Tğwo•ɁsMõ³ă‡AN£™MRkmEʕč™ÛbMjÝGu…IZ™—GPģ‡ãħE[iµBEuŸDPԛ~ª¼ętŠœ]ŒûG§€¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~Ż¸Y’I“] P‰umŝrƿ›‰›Iā‹[x‰edz‹L‘¯v¯s¬ÁY…~}…ťuŁŒg›ƋpÝĄ_ņī¶ÏSR´ÁP~ž¿Cyžċßdwk´Ss•X|t‰`Ä Èð€AªìÎT°¦Dd–€a^lĎDĶÚY°Ž`ĪŴǒˆ”àŠv\\ebŒZH„ŖR¬ŢƱùęO•ÑM­³FۃWp[ƒ" + ] + ], + encodeOffsets: [ + [[123806, 39303]], + [[123821, 39266]], + [[123742, 39256]], + [[123702, 39203]], + [[123649, 39066]], + [[123847, 38933]], + [[123580, 38839]], + [[123894, 37288]], + [[123043, 36624]], + [[123344, 38676]], + [[123522, 38857]], + [[123628, 38858]], + [[118260, 36742]] + ] + }, + properties: { cp: [117.000923, 36.675807], name: "山东", childNum: 13 } + }, + { + id: "410000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@•ýL™ùµP³swIÓxcŢĞð†´E®žÚPt†ĴXØx¶˜@«ŕŕQGƒ‹Yfa[şu“ßǩ™đš_X³ijÕčC]kbc•¥CS¯ëÍB©÷‹–³­Siˆ_}m˜YTtž³xlàcȂzÀD}ÂOQ³ÐTĨ¯†ƗòËŖ[hœł‹Ŧv~††}ÂZž«¤lPǕ£ªÝŴÅR§ØnhcŒtâk‡nύ­ľŹUÓÝdKuķ‡I§oTũÙďkęĆH¸ÓŒ\\ăŒ¿PcnS{wBIvɘĽ[GqµuŸŇôYgûƒZcaŽ©@½Õǽys¯}lgg@­C\\£as€IdÍuCQñ[L±ęk·‹ţb¨©kK—’»›KC²‘òGKmĨS`ƒ˜UQ™nk}AGē”sqaJ¥ĐGR‰ĎpCuÌy ã iMc”plk|tRk†ðœev~^‘´†¦ÜŽSí¿_iyjI|ȑ|¿_»d}qŸ^{“Ƈdă}Ÿtqµ`Ƴĕg}V¡om½fa™Ço³TTj¥„tĠ—Ry”K{ùÓjuµ{t}uËR‘iŸvGŠçJFjµŠÍyqΘàQÂFewixGw½Yŷpµú³XU›½ġy™łå‰kÚwZXˆ·l„¢Á¢K”zO„Λ΀jc¼htoDHr…|­J“½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ…Ťƒ]MÛfaQpě±ǽ¾]u­Fu‹÷nƒ™čįADp}AjmcEǒaª³o³ÆÍSƇĈÙDIzˑ赟^ˆKLœ—i—Þñ€[œƒaA²zz‰Ì÷Dœ|[šíijgf‚ÕÞd®|`ƒĆ~„oĠƑô³Ŋ‘D×°¯CsŠøÀ«ì‰UMhTº¨¸ǡîS–Ô„DruÂÇZ•ÖEŽ’vPZ„žW”~؋ÐtĄE¢¦Ðy¸bŠô´oŬ¬Ž²Ês~€€]®tªašpŎJ¨Öº„_ŠŔ–`’Ŗ^Ѝ\\Ĝu–”~m²Ƹ›¸fW‰ĦrƔ}Î^gjdfÔ¡J}\\n C˜¦þWxªJRÔŠu¬ĨĨmF†dM{\\d\\ŠYÊ¢ú@@¦ª²SŠÜsC–}fNècbpRmlØ^g„d¢aÒ¢CZˆZxvÆ¶N¿’¢T@€uCœ¬^ĊðÄn|žlGl’™Rjsp¢ED}€Fio~ÔNŽ‹„~zkĘHVsDzßjƒŬŒŠŢ`Pûàl¢˜\\ÀœEhŽİgÞē X¼Pk–„|m" + ], + encodeOffsets: [[118256, 37017]] + }, + properties: { cp: [113.665412, 34.757975], name: "河南", childNum: 1 } + }, + { + id: "420000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@AB‚"], + ["@@lskt"], + [ + "@@¾«}{ra®pîÃ\\™›{øCŠËyyB±„b\\›ò˜Ý˜jK›‡L ]ĎĽÌ’JyÚCƈćÎT´Å´pb©È‘dFin~BCo°BĎĚømvŒ®E^vǾ½Ĝ²Ro‚bÜeNŽ„^ĺ£R†¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I”¾®I†{GqpCgyl{‡£œÍƒÍyPL“¡ƒ¡¸kW‡xYlÙ抚ŁĢzœ¾žV´W¶ùŸo¾ZHxjwfx„GNÁ•³Xéæl¶‰EièIH‰ u’jÌQ~v|sv¶Ôi|ú¢Fh˜Qsğ¦ƒSiŠBg™ÐE^ÁÐ{–čnOÂȞUÎóĔ†ÊēIJ}Z³½Mŧïeyp·uk³DsѨŸL“¶_œÅuèw»—€¡WqÜ]\\‘Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟO‡ƒKÉġÿ×wg”÷IÅzCg†]m«ªGeçÃTC’«[‰t§{loWeC@ps_Bp‘­r‘„f_``Z|ei¡—oċMqow€¹DƝӛDYpûs•–‹Ykıǃ}s¥ç³[§ŸcYŠ§HK„«Qy‰]¢“wwö€¸ïx¼ņ¾Xv®ÇÀµRĠЋžHMž±cÏd„ƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy…¿³x¯N‰o‰|¹H™ÏÛm‹júË~Tš•u˜ęjCöAwě¬R’đl¯ Ñb­‰ŇT†Ŀ_[Œ‘IčĄʿnM¦ğ\\É[T·™k¹œ©oĕ@A¾w•ya¥Y\\¥Âaz¯ãÁ¡k¥ne£Ûw†E©Êō¶˓uoj_Uƒ¡cF¹­[Wv“P©w—huÕyBF“ƒ`R‹qJUw\\i¡{jŸŸEPïÿ½fć…QÑÀQ{ž‚°‡fLԁ~wXg—ītêݾ–ĺ‘Hdˆ³fJd]‹HJ²…E€ƒoU¥†HhwQsƐ»Xmg±çve›]Dm͂PˆoCc¾‹_h”–høYrŊU¶eD°Č_N~øĹĚ·`z’]Äþp¼…äÌQŒv\\rCŒé¾TnkžŐڀÜa‡“¼ÝƆĢ¶Ûo…d…ĔňТJq’Pb ¾|JŒ¾fXŠƐîĨ_Z¯À}úƲ‹N_ĒĊ^„‘ĈaŐyp»CÇĕKŠšñL³ŠġMŒ²wrIÒŭxjb[œžn«øœ˜—æˆàƒ ^²­h¯Ú€ŐªÞ¸€Y²ĒVø}Ā^İ™´‚LŠÚm„¥ÀJÞ{JVŒųÞŃx×sxxƈē ģMř–ÚðòIf–Ċ“Œ\\Ʈ±ŒdʧĘD†vČ_Àæ~DŒċ´A®µ†¨ØLV¦êHÒ¤" + ] + ], + encodeOffsets: [ + [[113712, 34000]], + [[115612, 30507]], + [[113649, 34054]] + ] + }, + properties: { cp: [114.298572, 30.584355], name: "湖北", childNum: 3 } + }, + { + id: "430000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@—n„FTs"], + [ + "@@ßÅÆችÔXr—†CO™“…ËR‘ïÿĩ­TooQyšÓ[‹ŅBE¬–ÎÓXa„į§Ã¸G °ITxp‰úxÚij¥Ïš–Ģ¾ŠedžÄ©ĸG…œàGh‚€M¤–Â_U}Ċ}¢pczfŠþg¤€”ÇòAV‘‹M" + ], + [ + "@@©K—ƒA·³CQ±Á«³BUŠƑ¹AŠtćOw™D]ŒJiØSm¯b£‘ylƒ›X…HËѱH•«–‘C^õľA–Å§¤É¥„ïyuǙuA¢^{ÌC´­¦ŷJ£^[†“ª¿‡ĕ~•Ƈ…•N… skóā‡¹¿€ï]ă~÷O§­@—Vm¡‹Qđ¦¢Ĥ{ºjԏŽŒª¥nf´•~ÕoŸž×Ûą‹MąıuZœmZcÒ IJĪ²SÊDŽŶ¨ƚƒ’CÖŎªQؼrŭŽ­«}NÏürʬŒmjr€@ĘrTW ­SsdHzƓ^ÇÂyUi¯DÅYlŹu{hTœ}mĉ–¹¥ě‰Dÿë©ıÓ[Oº£ž“¥ót€ł¹MՄžƪƒ`Pš…Di–ÛUŠ¾Å‌ìˆU’ñB“È£ýhe‰dy¡oċ€`pfmjP~‚kZa…ZsÐd°wj§ƒ@€Ĵ®w~^‚kÀÅKvNmX\\¨a“”сqvíó¿F„¤¡@ũÑVw}S@j}¾«pĂr–ªg àÀ²NJ¶¶Dô…K‚|^ª†Ž°LX¾ŴäPĪ±œ£EXd›”^¶›IJÞܓ~‘u¸ǔ˜Ž›MRhsR…e†`ÄofIÔ\\Ø  i”ćymnú¨cj ¢»–GČìƊÿШXeĈĀ¾Oð Fi ¢|[jVxrIQŒ„_E”zAN¦zLU`œcªx”OTu RLÄ¢dV„i`p˔vŎµªÉžF~ƒØ€d¢ºgİàw¸Áb[¦Zb¦–z½xBĖ@ªpº›šlS¸Ö\\Ĕ[N¥ˀmĎă’J\\‹ŀ`€…ňSڊĖÁĐiO“Ĝ«BxDõĚiv—ž–S™Ì}iùŒžÜnšÐºGŠ{Šp°M´w†ÀÒzJ²ò¨ oTçüöoÛÿñŽőФ‚ùTz²CȆȸǎŪƒƑÐc°dPÎŸğ˶[Ƚu¯½WM¡­Éž“’B·rížnZŸÒ `‡¨GA¾\\pē˜XhÆRC­üWGġu…T靧Ŏѝ©ò³I±³}_‘‹EÃħg®ęisÁPDmÅ{‰b[Rşs·€kPŸŽƥƒóRo”O‹ŸVŸ~]{g\\“êYƪ¦kÝbiċƵŠGZ»Ěõ…ó·³vŝž£ø@pyö_‹ëŽIkѵ‡bcѧy…×dY؎ªiþž¨ƒ[]f]Ņ©C}ÁN‡»hĻħƏ’ĩ" + ] + ], + encodeOffsets: [ + [[115640, 30489]], + [[112543, 27312]], + [[116690, 26230]] + ] + }, + properties: { cp: [112.982279, 28.19409], name: "湖南", childNum: 3 } + }, + { + id: "440000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@QdˆAua"], + ["@@ƒlxDLo"], + ["@@sbhNLo"], + ["@@Ă āŸ"], + ["@@WltO[["], + ["@@Krœ]S"], + ["@@e„„I]y"], + ["@@I|„Mym"], + ["@@ƒÛ³LSŒž¼Y"], + ["@@nvºB–ëui©`¾"], + ["@@zdšÛ›Jw®"], + ["@@†°…¯"], + ["@@a yAª¸ËJIx،@€ĀHAmßV¡o•fu•o"], + ["@@šs‰ŗÃÔėAƁ›ZšÄ ~°ČP‚‹äh"], + ["@@‹¶Ý’Ì‚vmĞh­ı‡Q"], + ["@@HœŠdSjĒ¢D}war…“u«ZqadYM"], + ["@@elŒ\\LqqU"], + ["@@~rMo\\"], + ["@@f„^ƒC"], + ["@@øPªoj÷ÍÝħXČx”°Q¨ıXNv"], + ["@@gÇƳˆŽˆ”oˆŠˆ[~tly"], + ["@@E–ÆC¿‘"], + ["@@OŽP"], + [ + "@@w‹†đóg‰™ĝ—[³‹¡VÙæÅöM̳¹pÁaËýý©D©Ü“JŹƕģGą¤{Ùū…ǘO²«BƱéA—Ò‰ĥ‡¡«BhlmtÃPµyU¯uc“d·w_bŝcīímGOŽ|KP’ȏ‡ŹãŝIŕŭŕ@Óoo¿ē‹±ß}Ž…ŭ‚ŸIJWÈCőâUâǙI›ğʼn©I›ijEׅÁ”³Aó›wXJþ±ÌŒÜӔĨ£L]ĈÙƺZǾĆĖMĸĤfŒÎĵl•ŨnȈ‘ĐtF”Š–FĤ–‚êk¶œ^k°f¶gŠŽœ}®Fa˜f`vXŲxl˜„¦–ÔÁ²¬ÐŸ¦pqÊ̲ˆi€XŸØRDÎ}†Ä@ZĠ’s„x®AR~®ETtĄZ†–ƈfŠŠHâÒÐA†µ\\S¸„^wĖkRzŠalŽŜ|E¨ÈNĀňZTŒ’pBh£\\ŒĎƀuXĖtKL–¶G|Ž»ĺEļĞ~ÜĢÛĊrˆO˜Ùîvd]nˆ¬VœÊĜ°R֟pM††–‚ƂªFbwžEÀˆ˜©Œž\\…¤]ŸI®¥D³|ˎ]CöAŤ¦…æ’´¥¸Lv¼€•¢ĽBaô–F~—š®²GÌҐEY„„œzk¤’°ahlV՞I^‹šCxĈPŽsB‰ƒºV‰¸@¾ªR²ĨN]´_eavSi‡vc•}p}Đ¼ƌkJœÚe thœ†_¸ ºx±ò_xN›Ë‹²‘@ƒă¡ßH©Ùñ}wkNÕ¹ÇO½¿£ĕ]ly_WìIžÇª`ŠuTÅxYĒÖ¼k֞’µ‚MžjJÚwn\\h‘œĒv]îh|’È›Ƅøègž¸Ķß ĉĈWb¹ƀdéʌNTtP[ŠöSvrCZžžaGuœbo´ŖÒÇА~¡zCI…özx¢„Pn‹•‰Èñ @ŒĥÒ¦†]ƞŠV}³ăĔñiiÄÓVépKG½Ä‘ÓávYo–C·sit‹iaÀy„ŧΡÈYDÑům}‰ý|m[węõĉZÅxUO}÷N¹³ĉo_qtă“qwµŁYلǝŕ¹tïÛUïmRCº…ˆĭ|µ›ÕÊK™½R‘ē ó]‘–GªęAx–»HO£|ām‡¡diď×YïYWªʼnOeÚtĐ«zđ¹T…ā‡úE™á²\\‹ķÍ}jYàÙÆſ¿Çdğ·ùTßÇţʄ¡XgWÀLJğ·¿ÃˆOj YÇ÷Qě‹i" + ] + ], + encodeOffsets: [ + [[117381, 22988]], + [[116552, 22934]], + [[116790, 22617]], + [[116973, 22545]], + [[116444, 22536]], + [[116931, 22515]], + [[116496, 22490]], + [[116453, 22449]], + [[113301, 21439]], + [[118726, 21604]], + [[118709, 21486]], + [[113210, 20816]], + [[115482, 22082]], + [[113171, 21585]], + [[113199, 21590]], + [[115232, 22102]], + [[115739, 22373]], + [[115134, 22184]], + [[113056, 21175]], + [[119573, 21271]], + [[119957, 24020]], + [[115859, 22356]], + [[116561, 22649]], + [[116285, 22746]] + ] + }, + properties: { cp: [113.280637, 23.125178], name: "广东", childNum: 24 } + }, + { + id: "450000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@H– TQ§•A"], + [ + "@@ĨʪƒLƒƊDÎĹĐCǦė¸zÚGn£¾›rªŀÜt¬@֛ڈSx~øOŒ˜ŶÐÂæȠ\\„ÈÜObĖw^oބLf¬°bI lTØB̈F£Ć¹gñĤaY“t¿¤VSñœK¸¤nM†¼‚JE±„½¸šŠño‹ÜCƆæĪ^ŠĚQÖ¦^‡ˆˆf´Q†üÜʝz¯šlzUĺš@쇀p¶n]sxtx¶@„~ÒĂJb©gk‚{°‚~c°`ԙ¬rV\\“la¼¤ôá`¯¹LC†ÆbŒxEræO‚v[H­˜„[~|aB£ÖsºdAĐzNÂðsŽÞƔ…Ĥªbƒ–ab`ho¡³F«èVloŽ¤™ÔRzpp®SŽĪº¨ÖƒºN…ij„d`’a”¦¤F³ºDÎńĀìŠCžĜº¦Ċ•~nS›|gźvZkCÆj°zVÈÁƔ]LÊFZg…čP­kini«‹qǀcz͔Y®¬Ů»qR×ō©DՄ‘§ƙǃŵTÉĩ±ŸıdÑnYY›IJvNĆƌØÜ Öp–}e³¦m‹©iÓ|¹Ÿħņ›|ª¦QF¢Â¬ʖovg¿em‡^ucà÷gՎuŒíÙćĝ}FĻ¼Ĺ{µHK•sLSđƃr‹č¤[Ag‘oS‹ŇYMÿ§Ç{Fśbky‰lQxĕƒ]T·¶[B…ÑÏGáşşƇe€…•ăYSs­FQ}­Bƒw‘tYğÃ@~…C̀Q ×W‡j˱rÉ¥oÏ ±«ÓÂ¥•ƒ€k—ŽwWűŒmcih³K›~‰µh¯e]lµ›él•Eģ‰•E“ďs‡’mǖŧē`ãògK_ÛsUʝ“ćğ¶hŒöŒO¤Ǜn³Žc‘`¡y‹¦C‘ez€YŠwa™–‘[ďĵűMę§]X˜Î_‚훘Û]é’ÛUćİÕBƣ±…dƒy¹T^džûÅÑŦ·‡PĻþÙ`K€¦˜…¢ÍeœĥR¿Œ³£[~Œäu¼dl‰t‚†W¸oRM¢ď\\zœ}Æzdvň–{ÎXF¶°Â_„ÒÂÏL©Ö•TmuŸ¼ãl‰›īkiqéfA„·Êµ\\őDc¥ÝF“y›Ôć˜c€űH_hL܋êĺШc}rn`½„Ì@¸¶ªVLŒŠhŒ‹\\•Ţĺk~ŽĠið°|gŒtTĭĸ^x‘vK˜VGréAé‘bUu›MJ‰VÃO¡…qĂXËS‰ģãlýàŸ_ju‡YÛÒB†œG^˜é֊¶§ŽƒEG”ÅzěƒƯ¤Ek‡N[kdåucé¬dnYpAyČ{`]þ¯T’bÜÈk‚¡Ġ•vŒàh„ÂƄ¢J" + ] + ], + encodeOffsets: [[[111707, 21520]], [[107619, 25527]]] + }, + properties: { cp: [108.320004, 22.82402], name: "广西", childNum: 2 } + }, + { + id: "460000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@š¦Ŝil¢”XƦ‘ƞò–ïè§ŞCêɕrŧůÇąĻõ™·ĉ³œ̅kÇm@ċȧƒŧĥ‰Ľʉ­ƅſ“ȓÒ˦ŝE}ºƑ[ÍĜȋ gÎfǐÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀœÐ¾jNðĀÒRŒšZdž™zÐŘΰH¨Ƣb²_Ġ " + ], + encodeOffsets: [[112750, 20508]] + }, + properties: { cp: [110.33119, 20.031971], name: "海南", childNum: 1 } + }, + { + id: "510000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@LqKr"], + [ + "@@Š[ĻéV£ž_ţġñpG •réÏ·~ąSfy×͂·ºſƽiÍıƣıĻmHH}siaX@iÇ°ÁÃ×t«ƒ­Tƒ¤J–JJŒyJ•ÈŠ`Ohߦ¡uËhIyCjmÿw…ZG……Ti‹SˆsO‰žB²ŸfNmsPaˆ{M{ŠõE‘^Hj}gYpaeuž¯‘oáwHjÁ½M¡pM“–uå‡mni{fk”\\oƒÎqCw†EZ¼K›ĝŠƒAy{m÷L‡wO×SimRI¯rK™õBS«sFe‡]fµ¢óY_ÆPRcue°Cbo׌bd£ŌIHgtrnyPt¦foaXďx›lBowz‹_{ÊéWiêE„GhܸºuFĈIxf®Ž•Y½ĀǙ]¤EyŸF²ċ’w¸¿@g¢§RGv»–áŸW`ÃĵJwi]t¥wO­½a[׈]`Ãi­üL€¦LabbTÀå’c}Íh™Æhˆ‹®BH€î|Ék­¤S†y£„ia©taį·Ɖ`ō¥Uh“O…ƒĝLk}©Fos‰´›Jm„µlŁu—…ø–nÑJWΪ–YÀïAetTžŅ‚ӍG™Ë«bo‰{ıwodƟ½ƒžOġܑµxàNÖ¾P²§HKv¾–]|•B‡ÆåoZ`¡Ø`ÀmºĠ~ÌЧnDž¿¤]wğ@sƒ‰rğu‰~‘Io”[é±¹ ¿žſđӉ@q‹gˆ¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@ỗs›Zϕ‹œÅĭ€Ƌ•ěpwDóÖሯneQˌq·•GCœýS]xŸ·ý‹q³•O՜Œ¶Qzßti{ř‰áÍÇWŝŭñzÇW‹pç¿JŒ™‚Xœĩè½cŒF–ÂLiVjx}\\N†ŇĖ¥Ge–“JA¼ÄHfÈu~¸Æ«dE³ÉMA|b˜Ò…˜ćhG¬CM‚õŠ„ƤąAvƒüV€éŀ‰_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»Ÿ“˜ÕZ³ġqDo‰y`L¬gdp°şŠp¦ėìÅĮZŽ°Iä”h‚‘ˆzŠĵœf²å ›ĚрKp‹IN|‹„Ñz]ń……·FU×é»R³™MƒÉ»GM«€ki€™ér™}Ã`¹ăÞmȝnÁîRǀ³ĜoİzŔwǶVÚ£À]ɜ»ĆlƂ²Ġ…þTº·àUȞÏʦ¶†I’«dĽĢdĬ¿–»Ĕ׊h\\c¬†ä²GêëĤł¥ÀǿżÃÆMº}BÕĢyFVvw–ˆxBèĻĒ©Ĉ“tCĢɽŠȣ¦āæ·HĽî“ôNԓ~^¤Ɗœu„œ^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ‘®Z´ğ~Sn|ªWÚ©òzPOȸ‚bð¢|‹øĞŠŒœŒQìÛÐ@Ğ™ǎRS¤Á§d…i“´ezÝúØã]Hq„kIŸþËQǦÃsǤ[E¬ÉŪÍxXƒ·ÖƁİlƞ¹ª¹|XÊwn‘ÆƄmÀêErĒtD®ċæcQƒ”E®³^ĭ¥©l}äQto˜ŖÜqƎkµ–„ªÔĻĴ¡@Ċ°B²Èw^^RsºTĀ£ŚæœQP‘JvÄz„^Đ¹Æ¯fLà´GC²‘dt˜­ĀRt¼¤ĦOðğfÔðDŨŁĞƘïžPȆ®âbMüÀXZ ¸£@Ś›»»QÉ­™]d“sÖ×_͖_ÌêŮPrĔĐÕGĂeZÜîĘqBhtO ¤tE[h|Y‹Ô‚ZśÎs´xº±UŒ’ñˆt|O’ĩĠºNbgþŠJy^dÂY Į„]Řz¦gC‚³€R`ĀŠz’¢AjŒ¸CL„¤RÆ»@­Ŏk\\Ç´£YW}z@Z}‰Ã¶“oû¶]´^N‡Ò}èN‚ª–P˜Íy¹`S°´†ATe€VamdUĐwʄvĮÕ\\ƒu‹Æŗ¨Yp¹àZÂm™Wh{á„}WØǍ•Éüw™ga§áCNęÎ[ĀÕĪgÖɪX˜øx¬½Ů¦¦[€—„NΆL€ÜUÖ´òrÙŠxR^–†J˜k„ijnDX{Uƒ~ET{ļº¦PZc”jF²Ė@Žp˜g€ˆ¨“B{ƒu¨ŦyhoÚD®¯¢˜ WòàFΤ¨GDäz¦kŮPœġq˚¥À]€Ÿ˜eŽâÚ´ªKxī„Pˆ—Ö|æ[xäJÞĥ‚s’NÖ½ž€I†¬nĨY´®Ð—ƐŠ€mD™ŝuäđđEb…e’e_™v¡}ìęNJē}q”É埁T¯µRs¡M@}ůa†a­¯wvƉåZwž\\Z{åû^›" + ] + ], + encodeOffsets: [[[108815, 30935]], [[110617, 31811]]] + }, + properties: { cp: [104.065735, 30.659462], name: "四川", childNum: 2 } + }, + { + id: "520000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@†G\\†lY£‘in"], + ["@@q‚|ˆ‚mc¯tχVSÎ"], + [ + "@@hÑ£Is‡NgßH†›HªķÃh_¹ƒ¡ĝħń¦uيùŽgS¯JHŸ|sÝÅtÁïyMDč»eÕtA¤{b\\}—ƒG®u\\åPFq‹wÅaD…žK°ºâ_£ùbµ”mÁ‹ÛœĹM[q|hlaªāI}тƒµ@swtwm^oµˆD鼊yV™ky°ÉžûÛR…³‚‡eˆ‡¥]RՋěħ[ƅåÛDpŒ”J„iV™™‰ÂF²I…»mN·£›LbÒYb—WsÀbŽ™pki™TZĄă¶HŒq`……ĥ_JŸ¯ae«ƒKpÝx]aĕÛPƒÇȟ[ÁåŵÏő—÷Pw}‡TœÙ@Õs«ĿÛq©½œm¤ÙH·yǥĘĉBµĨÕnđ]K„©„œá‹ŸG纍§Õßg‡ǗĦTèƤƺ{¶ÉHÎd¾ŚÊ·OÐjXWrãLyzÉAL¾ę¢bĶėy_qMĔąro¼hĊžw¶øV¤w”²Ĉ]ʚKx|`ź¦ÂÈdr„cȁbe¸›`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_pН`oÒhŽ¶pa‚^ÓĔ}D»^Xyœ`d˜[Kv…JPhèhCrĂĚÂ^Êƌ wˆZL­Ġ£šÁbrzOIl’MM”ĪŐžËr×ÎeŦŽtw|Œ¢mKjSǘňĂStÎŦEtqFT†¾†E쬬ôxÌO¢Ÿ KŠ³ŀºäY†„”PVgŎ¦Ŋm޼VZwVlŒ„z¤…ž£Tl®ctĽÚó{G­A‡ŒÇgeš~Αd¿æaSba¥KKûj®_ć^\\ؾbP®¦x^sxjĶI_Ä X‚⼕Hu¨Qh¡À@Ëô}Ž±žGNìĎlT¸ˆ…`V~R°tbÕĊ`¸úÛtπFDu€[ƒMfqGH·¥yA‰ztMFe|R‚_Gk†ChZeÚ°to˜v`x‹b„ŒDnÐ{E}šZ˜è€x—†NEފREn˜[Pv@{~rĆAB§‚EO¿|UZ~ì„Uf¨J²ĂÝƀ‚sª–B`„s¶œfvö¦ŠÕ~dÔq¨¸º»uù[[§´sb¤¢zþFœ¢Æ…Àhˆ™ÂˆW\\ıŽËI݊o±ĭŠ£þˆÊs}¡R]ŒěƒD‚g´VG¢‚j±®è†ºÃmpU[Á›‘Œëº°r›ÜbNu¸}Žº¼‡`ni”ºÔXĄ¤¼Ôdaµ€Á_À…†ftQQgœR—‘·Ǔ’v”}Ýלĵ]µœ“Wc¤F²›OĩųãW½¯K‚©…]€{†LóµCIµ±Mß¿hŸ•©āq¬o‚½ž~@i~TUxŪÒ¢@ƒ£ÀEîôruń‚”“‚b[§nWuMÆLl¿]x}ij­€½" + ] + ], + encodeOffsets: [ + [[112158, 27383]], + [[112105, 27474]], + [[112095, 27476]] + ] + }, + properties: { cp: [106.713478, 26.578343], name: "贵州", childNum: 3 } + }, + { + id: "530000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@[„ùx½}ÑRH‘YīĺûsÍn‘iEoã½Ya²ė{c¬ĝg•ĂsA•ØÅwď‚õzFjw}—«Dx¿}UũlŸê™@•HÅ­F‰¨ÇoJ´Ónũuą¡Ã¢pÒŌ“Ø TF²‚xa²ËX€‚cʋlHîAßËŁkŻƑŷÉ©h™W­æßU‡“Ës¡¦}•teèƶStǀÇ}Fd£j‹ĈZĆÆ‹¤T‚č\\Dƒ}O÷š£Uˆ§~ŃG™‚åŃDĝ¸œTsd¶¶Bªš¤u¢ŌĎo~t¾ÍŶÒtD¦Ú„iôö‰€z›ØX²ghįh½Û±¯€ÿm·zR¦Ɵ`ªŊÃh¢rOԍ´£Ym¼èêf¯ŪĽn„†cÚbŒw\\zlvWžªâˆ ¦g–mĿBş£¢ƹřbĥkǫßeeZkÙIKueT»sVesb‘aĕ  ¶®dNœĄÄpªyŽ¼—„³BE˜®l‡ŽGœŭCœǶwêżĔÂe„pÍÀQƞpC„–¼ŲÈ­AÎô¶R„ä’Q^Øu¬°š_Èôc´¹ò¨P΢hlϦ´Ħ“Æ´sâDŽŲPnÊD^¯°’Upv†}®BP̪–jǬx–Söwlfòªv€qĸ|`H€­viļ€ndĜ­Ćhň•‚em·FyށqóžSį¯‘³X_ĞçêtryvL¤§z„¦c¦¥jnŞk˜ˆlD¤øz½ĜàžĂŧMÅ|áƆàÊcðÂF܎‚áŢ¥\\\\º™İøÒÐJĴ‡„îD¦zK²ǏÎEh~’CD­hMn^ÌöÄ©ČZÀžaü„fɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~Äqššê€ljN¬¼H„ÊšNQ´ê¼VظE††^ŃÒyŒƒM{ŒJLoÒœęæŸe±Ķ›y‰’‡gã“¯JYÆĭĘëo¥Š‰o¯hcK«z_pŠrC´ĢÖY”—¼ v¸¢RŽÅW³Â§fǸYi³xR´ďUˊ`êĿU„û€uĆBƒƣö‰N€DH«Ĉg†——Ñ‚aB{ÊNF´¬c·Åv}eÇÃGB»”If•¦HňĕM…~[iwjUÁKE•Ž‹¾dĪçW›šI‹èÀŒoÈXòyŞŮÈXâÎŚŠj|àsRy‹µÖ›–Pr´þŒ ¸^wþTDŔ–Hr¸‹žRÌmf‡żÕâCôox–ĜƌÆĮŒ›Ð–œY˜tâŦÔ@]ÈǮƒ\\Ī¼Ä£UsȯLbîƲŚºyh‡rŒŠ@ĒԝƀŸÀ²º\\êp“’JŠ}ĠvŠqt„Ġ@^xÀ£È†¨mËÏğ}n¹_¿¢×Y_æpˆÅ–A^{½•Lu¨GO±Õ½ßM¶w’ÁĢۂP‚›Ƣ¼pcIJxŠ|ap̬HšÐŒŊSfsðBZ¿©“XÏÒK•k†÷Eû¿‰S…rEFsÕūk”óVǥʼniTL‚¡n{‹uxţÏh™ôŝ¬ğōN“‘NJkyPaq™Âğ¤K®‡YŸxÉƋÁ]āęDqçgOg†ILu—\\_gz—]W¼ž~CÔē]bµogpў_oď`´³Țkl`IªºÎȄqÔþž»E³ĎSJ»œ_f·‚adÇqƒÇc¥Á_Źw{™L^ɱćx“U£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣG˛÷Ÿk°_^ý|_zċBZocmø¯hhcæ\\lˆMFlư£Ĝ„ÆyH“„F¨‰µêÕ]—›HA…àӄ^it `þßäkŠĤÎT~Wlÿ¨„ÔPzUC–NVv [jâôDôď[}ž‰z¿–msSh‹¯{jïğl}šĹ[–őŒ‰gK‹©U·µË@¾ƒm_~q¡f¹…ÅË^»‘f³ø}Q•„¡Ö˳gͱ^ǁ…\\ëÃA_—¿bW›Ï[¶ƛ鏝£F{īZgm@|kHǭƁć¦UĔťƒ×ë}ǝƒeďºȡȘÏíBə£āĘPªij¶“ʼnÿ‡y©n‰ď£G¹¡I›Š±LÉĺÑdĉ܇W¥˜‰}g˜Á†{aqÃ¥aŠıęÏZ—ï`" + ], + encodeOffsets: [[104636, 22969]] + }, + properties: { cp: [102.712251, 25.040609], name: "云南", childNum: 1 } + }, + { + id: "540000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@hžľxŽŖ‰xƒÒVŽ†ºÅâAĪÝȆµę¯Ňa±r_w~uSÕň‘qOj]ɄQ…£Z……UDûoY’»©M[‹L¼qãË{V͕çWViŽ]ë©Ä÷àyƛh›ÚU°ŒŒa”d„cQƒ~Mx¥™cc¡ÙaSyF—ցk­ŒuRýq¿Ôµ•QĽ³aG{¿FµëªéĜÿª@¬·–K‰·àariĕĀ«V»Ŷ™Ĵū˜gèLǴŇƶaf‹tŒèBŚ£^Šâ†ǐÝ®–šM¦ÁǞÿ¬LhŸŽJ¾óƾƺcxw‹f]Y…´ƒ¦|œQLn°aœdĊ…œ\\¨o’œǀÍŎœ´ĩĀd`tÊQŞŕ|‚¨C^©œĈ¦„¦ÎJĊ{ŽëĎjª²rЉšl`¼Ą[t|¦St辉PŒÜK¸€d˜Ƅı]s¤—î_v¹ÎVòŦj˜£Əsc—¬_Ğ´|Ł˜¦AvŽ¦w`ăaÝaa­¢e¤ı²©ªSªšÈMĄwžÉØŔì@T‘¤—Ę™\\õª@”þo´­xA s”ÂtŎKzó´ÇĊµ¢rž^nĊ­Æ¬×üGž¢‚³ {âĊ]š™G‚~bÀgVjzlhǶf€žOšfdŠ‰ªB]pj„•TO–tĊ‚n¤}®¦ƒČ¥d¢¼»ddš”Y¼Žt—¢eȤJ¤}Ǿ¡°§¤AГlc@ĝ”sªćļđAç‡wx•UuzEÖġ~AN¹ÄÅȀŻ¦¿ģŁéì±H…ãd«g[؉¼ēÀ•cīľġ¬cJ‘µ…ÐʥVȝ¸ßS¹†ý±ğkƁ¼ą^ɛ¤Ûÿ‰b[}¬ōõÃ]ËNm®g@•Bg}ÍF±ǐyL¥íCˆƒIij€Ï÷њį[¹¦[⚍EÛïÁÉdƅß{âNÆāŨߝ¾ě÷yC£‡k­´ÓH@¹†TZ¥¢įƒ·ÌAЧ®—Zc…v½ŸZ­¹|ŕWZqgW“|ieZÅYVӁqdq•bc²R@†c‡¥Rã»Ge†ŸeƃīQ•}J[ғK…¬Ə|o’ėjġĠÑN¡ð¯EBčnwôɍėªƒ²•CλŹġǝʅįĭạ̃ūȹ]ΓͧgšsgȽóϧµǛ†ęgſ¶ҍć`ĘąŌJޚä¤rÅň¥ÖÁUětęuůÞiĊÄÀ\\Æs¦ÓRb|Â^řÌkÄŷ¶½÷‡f±iMݑ›‰@ĥ°G¬ÃM¥n£Øą‚ğ¯ß”§aëbéüÑOčœk£{\\‘eµª×M‘šÉfm«Ƒ{Å׃Gŏǩãy³©WÑăû‚··‘Q—òı}¯ã‰I•éÕÂZ¨īès¶ZÈsŽæĔTŘvŽgÌsN@îá¾ó@‰˜ÙwU±ÉT廣TđŸWxq¹Zo‘b‹s[׌¯cĩv‡Œėŧ³BM|¹k‰ªħ—¥TzNYnݍßpęrñĠĉRS~½ŠěVVŠµ‚õ‡«ŒM££µB•ĉ¥áºae~³AuĐh`Ü³ç@BۘïĿa©|z²Ý¼D”£àč²‹ŸƒIƒû›I ā€óK¥}rÝ_Á´éMaň¨€~ªSĈ½Ž½KÙóĿeƃÆBŽ·¬ën×W|Uº}LJrƳ˜lŒµ`bÔ`QˆˆÐÓ@s¬ñIŒÍ@ûws¡åQÑßÁ`ŋĴ{Ī“T•ÚÅTSij‚‹Yo|Ç[ǾµMW¢ĭiÕØ¿@˜šMh…pÕ]j†éò¿OƇĆƇp€êĉâlØw–ěsˆǩ‚ĵ¸c…bU¹ř¨WavquSMzeo_^gsÏ·¥Ó@~¯¿RiīB™Š\\”qTGªÇĜçPoŠÿfñòą¦óQīÈáP•œābß{ƒZŗĸIæńhnszÁCËìñšÏ·ąĚÝUm®ó­L·ăU›Èíoù´Êj°ŁŤ_uµ^‘°Œìǖ@tĶĒ¡Æ‡M³Ģ«˜İĨÅ®ğ†RŽāð“ggheÆ¢z‚Ê©Ô\\°ÝĎz~ź¤Pn–MĪÖB£Ÿk™n鄧żćŠ˜ĆK„Ē°¼L¶è‰âz¨u¦¥LDĘz¬ýÎmĘd¾ß”Fz“hg²™Fy¦ĝ¤ċņbΛ@y‚Ąæm°NĮZRÖíŽJ²öLĸÒ¨Y®ƌÐV‰à˜tt_ڀÂyĠzž]Ţh€zĎ{†ĢX”ˆc|šÐqŽšfO¢¤ög‚ÌHNŽ„PKŖœŽ˜Uú´xx[xˆvĐCûĀŠìÖT¬¸^}Ìsòd´_Ž‡KgžLĴ…ÀBon|H@–Êx˜—¦BpŰˆŌ¿fµƌA¾zLjRxŠ¶F”œkĄźRzŀˆ~¶[”´Hnª–VƞuĒ­È¨ƎcƽÌm¸ÁÈM¦x͊ëÀxdžB’šú^´W†£–d„kɾĬpœw‚˂ØɦļĬIŚœÊ•n›Ŕa¸™~J°î”lɌxĤÊÈðhÌ®‚g˜T´øŽàCˆŽÀ^ªerrƘdž¢İP|Ė ŸWœªĦ^¶´ÂL„aT±üWƜ˜ǀRšŶUńšĖ[QhlLüA†‹Ü\\†qR›Ą©" + ], + encodeOffsets: [[90849, 37210]] + }, + properties: { cp: [91.132212, 29.660361], name: "西藏", childNum: 1 } + }, + { + id: "610000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@˜p¢—ȮµšûG™Ħ}Ħšðǚ¶òƄ€jɂz°{ºØkÈęâ¦jª‚Bg‚\\œċ°s¬Ž’]jžú ‚E”Ȍdž¬s„t‡”RˆÆdĠݎwܔ¸ôW¾ƮłÒ_{’Ìšû¼„jº¹¢GǪÒ¯ĘƒZ`ºŊƒecņąš~BÂgzpâēòYǠȰÌTΨÂWœ|fcŸă§uF—Œ@NŸ¢XLƒŠRMº[ğȣſï|¥J™kc`sʼnǷ’Y¹‹W@µ÷K…ãï³ÛIcñ·VȋڍÒķø©—þ¥ƒy‚ÓŸğęmWµÎumZyOŅƟĥÓ~sÑL¤µaŅY¦ocyZ{‰y c]{ŒTa©ƒ`U_Ěē£ωÊƍKù’K¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑd‘ŠìUYƒŽO‘uF–ÕÈYvÁCqӃT•Ǣí§·S¹NgŠV¬ë÷Át‡°Dد’C´ʼnƒópģ}„ċcE˅FŸŸéGU¥×K…§­¶³B‹Č}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO…ÿEËߌ•ĤNĔŸwƇˆÄŠńwĪ­Šo[„_KÓª³“ÙnK‰Çƒěœÿ]ď€ă_d©·©Ýŏ°Ù®g]±„Ÿ‡ß˜å›—¬÷m\\›iaǑkěX{¢|ZKlçhLt€Ňîŵ€œè[€É@ƉĄEœ‡tƇÏ˜³­ħZ«mJ…›×¾‘MtÝĦ£IwÄå\\Õ{‡˜ƒOwĬ©LÙ³ÙgBƕŀr̛ĢŭO¥lãyC§HÍ£ßEñŸX¡—­°ÙCgpťz‘ˆb`wI„vA|§”‡—hoĕ@E±“iYd¥OĻ¹S|}F@¾oAO²{tfžÜ—¢Fǂ҈W²°BĤh^Wx{@„¬‚­F¸¡„ķn£P|ŸªĴ@^ĠĈæb–Ôc¶l˜Yi…–^Mi˜cĎ°Â[ä€vï¶gv@À“Ĭ·lJ¸sn|¼u~a]’ÆÈtŌºJp’ƒþ£KKf~Š¦UbyäIšĺãn‡Ô¿^­žŵMT–hĠܤko¼Ŏìąǜh`[tŒRd²IJ_œXPrɲ‰l‘‚XžiL§àƒ–¹ŽH˜°Ȧqº®QC—bA†„ŌJ¸ĕÚ³ĺ§ `d¨YjžiZvRĺ±öVKkjGȊĐePОZmļKÀ€‚[ŠŽ`ösìh†ïÎoĬdtKÞ{¬èÒÒBŒÔpIJÇĬJŊ¦±J«ˆY§‹@·pH€µàåVKe›pW†ftsAÅqC·¬ko«pHÆuK@oŸHĆۄķhx“e‘n›S³àǍrqƶRbzy€¸ËАl›¼EºpĤ¼Œx¼½~Ğ’”à@†ÚüdK^ˆmÌSj" + ], + encodeOffsets: [[110234, 38774]] + }, + properties: { cp: [108.948024, 34.263161], name: "陕西", childNum: 1 } + }, + { + id: "620000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@VuUv"], + [ + "@@ũ‹EĠtt~nkh`Q‰¦ÅÄÜdw˜Ab×ĠąJˆ¤DüègĺqBqœj°lI¡ĨÒ¤úSHbš‡ŠjΑBŠ°aZˆ¢KJŽ’O[|A£žDx}Nì•HUnrk„ kp€¼Y kMJn[aG‚áÚÏ[½rc†}aQxOgsPMnUs‡nc‹Z…ž–sKúvA›t„Þġ’£®ĀYKdnFwš¢JE°”Latf`¼h¬we|€Æ‡šbj}GA€·~WŽ”—`†¢MC¤tL©IJ°qdf”O‚“bÞĬ¹ttu`^ZúE`Œ[@„Æsîz®¡’C„ƳƜG²“R‘¢R’m”fŽwĸg܃‚ą G@pzJM½mŠhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬‡²I‚¥IʼnÈīoı‹ÓÑAçÑ|«LÝcspīðÍg…të_õ‰\\ĉñLYnĝg’ŸRǡÁiHLlõUĹ²uQjYi§Z_c¨Ÿ´ĹĖÙ·ŋI…ƒaBD˜­R¹ȥr—¯G•ºß„K¨jWk’ɱŠOq›Wij\\a­‹Q\\sg_ĆǛōëp»£lğۀgS•ŶN®À]ˆÓäm™ĹãJaz¥V}‰Le¤L„ýo‘¹IsŋÅÇ^‘Žbz…³tmEÁ´aŠ¹cčecÇN•ĊãÁ\\č¯—dNj•]j†—ZµkÓda•ćå]ğij@ ©O{¤ĸm¢ƒE·®ƒ«|@Xwg]Aģ±¯‡XǁÑdzªc›wQÚŝñsÕ³ÛV_ýƒ˜¥\\ů¥©¾÷w—Ž©WÕÊĩhÿÖÁRo¸V¬âDb¨šhûx–Ê×nj~Zâƒg|šXÁnßYoº§ZÅŘvŒ[„ĭÖʃuďxcVbnUSf…B¯³_Tzº—ΕO©çMÑ~Mˆ³]µ^püµ”ŠÄY~y@X~¤Z³€[Èōl@®Å¼£QKƒ·Di‹¡By‘ÿ‰Q_´D¥hŗyƒ^ŸĭÁZ]cIzý‰ah¹MĪğP‘s{ò‡‹‘²Vw¹t³Ŝˁ[ŽÑ}X\\gsFŸ£sPAgěp×ëfYHāďÖqēŭOÏë“dLü•\\iŒ”t^c®šRʺ¶—¢H°mˆ‘rYŸ£BŸ¹čIoľu¶uI]vģSQ{ƒUŻ”Å}QÂ|̋°ƅ¤ĩŪU ęĄžÌZҞ\\v˜²PĔ»ƢNHƒĂyAmƂwVmž`”]ȏb•”H`‰Ì¢²ILvĜ—H®¤Dlt_„¢JJÄämèÔDëþgºƫ™”aʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b…ð÷’Žˆ‡®‚”üs”zMzÖĖQdȨý†v§Tè|ªH’þa¸|šÐ ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v†·À|\\ƁĚN´Ĝ€çèÁz]ġ¤²¨QÒŨTIl‡ªťØ}¼˗ƦvÄùØE‹’«Fï˛Iq”ōŒTvāÜŏ‚íÛߜÛV—j³âwGăÂíNOŠˆŠPìyV³ʼnĖýZso§HіiYw[߆\\X¦¥c]ÔƩÜ·«j‡ÐqvÁ¦m^ċ±R™¦΋ƈťĚgÀ»IïĨʗƮŽ°Ɲ˜ĻþÍAƉſ±tÍEÕÞāNU͗¡\\ſčåÒʻĘm ƭÌŹöʥ’ëQ¤µ­ÇcƕªoIýˆ‰Iɐ_mkl³ă‰Ɠ¦j—¡Yz•Ňi–}Msßõ–īʋ —}ƒÁVmŸ_[n}eı­Uĥ¼‘ª•I{ΧDӜƻėoj‘qYhĹT©oūĶ£]ďxĩ‹ǑMĝ‰q`B´ƃ˺Ч—ç~™²ņj@”¥@đ´ί}ĥtPńǾV¬ufӃÉC‹tÓ̻‰…¹£G³€]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼ‚ĤŊɲĖ­Kq´ï¦—ºĒDzņɾªǀÞĈĂD†½ĄĎÌŗĞrôñnŽœN¼â¾ʄľԆ|DŽŽ֦ज़ȗlj̘̭ɺƅêgV̍ʆĠ·ÌĊv|ýĖÕWĊǎÞ´õ¼cÒÒBĢ͢UĜð͒s¨ňƃLĉÕÝ@ɛƯ÷¿Ľ­ĹeȏijëCȚDŲyê×Ŗyò¯ļcÂßY…tÁƤyAã˾J@ǝrý‹‰@¤…rz¸oP¹ɐÚyᐇHŸĀ[Jw…cVeȴϜ»ÈŽĖ}ƒŰŐèȭǢόĀƪÈŶë;Ñ̆ȤМľĮEŔ—ĹŊũ~ËUă{ŸĻƹɁύȩþĽvĽƓÉ@ē„ĽɲßǐƫʾǗĒpäWÐxnsÀ^ƆwW©¦cÅ¡Ji§vúF¶Ž¨c~c¼īŒeXǚ‹\\đ¾JŽwÀďksãA‹fÕ¦L}wa‚o”Z’‹D½†Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LF‹LzĈ„ôe]gx}•|KK}xklL]c¦£fRtív¦†PĤoH{tK" + ] + ], + encodeOffsets: [[[108619, 36299]], [[108589, 36341]]] + }, + properties: { cp: [103.823557, 36.058039], name: "甘肃", childNum: 2 } + }, + { + id: "630000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@InJm"], + [ + "@@CƒÆ½OŃĦsΰ~Ē³¦@@“Ņiš±è}ؘƄ˹A³r_ĞŠǒNĪŒĐw¤^ŬĵªpĺSZg’rpiƼĘԛ¨C|͖J’©Ħ»®VIJ~f\\m `Un„˜~ʌŸ•ĬàöNt•~ňjy–¢Zi˜Ɣ¥ĄŠk´nl`JʇŠJþ©pdƖ®È£¶ìRʦ‘źõƮËnŸʼėæÑƀĎ[‚˜¢VÎĂMÖÝÎF²sƊƀÎBļýƞ—¯ʘƭðħ¼Jh¿ŦęΌƇš¥²Q]Č¥nuÂÏriˆ¸¬ƪÛ^Ó¦d€¥[Wà…x\\ZŽjҕ¨GtpþYŊĕ´€zUO뇉P‰îMĄÁxH´á˜iÜUà›îÜՁĂÛSuŎ‹r“œJð̬EŒ‘FÁú×uÃÎkr“Ē{V}İ«O_ÌËĬ©ŽÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u…ºµ[gt£¸OƤĿéYŸõ·kĀŸq]juw¥Dĩƍ€õÇPéĽG‘ž©ã‡¤G…uȧþRcÕĕNy“yût“ˆ­‡ø‘†ï»a½ē¿BMoį£ŸÍj}éZËqbʍš“Ƭh¹ìÿÓAçãnIáI`ƒks£CG­ě˜Uy×Cy•…’Ÿ@¶ʡÊBnāzG„ơMē¼±O÷õJËĚăVŸĪũƆ£Œ¯{ËL½Ìzż“„VR|ĠTbuvJvµhĻĖH”Aëáa…­OÇðñęNw‡…œľ·L›mI±íĠĩPÉ×®ÿs—’cB³±JKßĊ«`…ađ»·QAmO’‘Vţéÿ¤¹SQt]]Çx€±¯A@ĉij¢Óļ©•ƒl¶ÅÛr—ŕspãRk~¦ª]Į­´“FR„åd­ČsCqđéFn¿Åƃm’Éx{W©ºƝºįkÕƂƑ¸wWūЩÈFž£\\tÈ¥ÄRÈýÌJ ƒlGr^×äùyÞ³fj”c†€¨£ÂZ|ǓMĝšÏ@ëÜőR‹›ĝ‰Œ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³’­ÞIňµç½©C¡į÷¯B»|St»›]vƒųƒs»”}MÓ ÿʪƟǭA¡fs˜»PY¼c¡»¦c„ċ­¥£~msĉP•–Siƒ^o©A‰Šec‚™PeǵŽkg‚yUi¿h}aH™šĉ^|ᴟ¡HØûÅ«ĉ®]m€¡qĉ¶³ÈyôōLÁst“BŸ®wn±ă¥HSòėš£˜S’ë@לÊăxÇN©™©T±ª£IJ¡fb®ÞbŽb_Ą¥xu¥B—ž{łĝ³«`d˜Ɛt—¤ťiñžÍUuºí`£˜^tƃIJc—·ÛLO‹½Šsç¥Ts{ă\\_»™kϊ±q©čiìĉ|ÍIƒ¥ć¥›€]ª§D{ŝŖÉR_sÿc³Īō›ƿΑ›§p›[ĉ†›c¯bKm›R¥{³„Z†e^ŽŒwx¹dƽŽôIg §Mĕ ƹĴ¿—ǣÜ̓]‹Ý–]snåA{‹eŒƭ`ǻŊĿ\\ijŬű”YÂÿ¬jĖqŽßbŠ¸•L«¸©@ěĀ©ê¶ìÀEH|´bRľž–Ó¶rÀQþ‹vl®Õ‚E˜TzÜdb ˜hw¤{LR„ƒd“c‹b¯‹ÙVgœ‚ƜßzÃô쮍^jUèXΖ|UäÌ»rKŽ\\ŒªN‘¼pZCü†VY††¤ɃRi^rPҒTÖ}|br°qňbĚ°ªiƶGQ¾²„x¦PœmlŜ‘[Ĥ¡ΞsĦŸÔÏâ\\ªÚŒU\\f…¢N²§x|¤§„xĔsZPòʛ²SÐqF`ª„VƒÞŜĶƨVZŒÌL`ˆ¢dŐIqr\\oäõ–F礻Ŷ×h¹]Clـ\\¦ďÌį¬řtTӺƙgQÇÓHţĒ”´ÃbEÄlbʔC”|CˆŮˆk„Ʈ[ʼ¬ňœ´KŮÈΰÌĪ¶ƶlð”ļA†TUvdTŠG†º̼ŠÔ€ŒsÊDԄveOg" + ] + ], + encodeOffsets: [[[105308, 37219]], [[95370, 40081]]] + }, + properties: { cp: [101.778916, 36.623178], name: "青海", childNum: 2 } + }, + { + id: "640000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + [ + "@@KëÀęĞ«OęȿȕŸı]ʼn¡åįÕÔ«Ǵõƪ™ĚQÐZhv K°›öqÀѐS[ÃÖHƖčË‡nL]ûc…Ùß@‚“ĝ‘¾}w»»‹oģF¹œ»kÌÏ·{zPƒ§B­¢íyÅt@ƒ@áš]Yv_ssģ¼i߁”ĻL¾ġsKD£¡N_…“˜X¸}B~Haiˆ™Åf{«x»ge_bs“KF¯¡Ix™mELcÿZ¤­Ģ‘ƒÝœsuBLù•t†ŒYdˆmVtNmtOPhRw~bd…¾qÐ\\âÙH\\bImlNZŸ»loƒŸqlVm–Gā§~QCw¤™{A\\‘PKŸNY‡¯bF‡kC¥’sk‹Šs_Ã\\ă«¢ħkJi¯r›rAhĹûç£CU‡ĕĊ_ԗBixÅُĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~–hw^‚ófćƒKyEŒ­K­zuÔ¡qQ¤xZÑ¢^ļöܾEpž±âbÊÑÆ^fk¬…NC¾‘Œ“YpxbK~¥Že֎ŒäBlt¿Đx½I[ĒǙŒWž‹f»Ĭ}d§dµùEuj¨‚IÆ¢¥dXªƅx¿]mtÏwßRĶŒX¢͎vÆzƂZò®ǢÌʆCrâºMÞzžÆMҔÊÓŊZľ–r°Î®Ȉmª²ĈUªĚøºˆĮ¦ÌĘk„^FłĬhĚiĀĖ¾iİbjÕ" + ], + ["@@mfwěwMrŢªv@G‰"] + ], + encodeOffsets: [[[109366, 40242]], [[108600, 36303]]] + }, + properties: { cp: [106.278179, 38.46637], name: "宁夏", childNum: 2 } + }, + { + id: "650000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@QØĔ²X¨”~ǘBºjʐßØvK”ƔX¨vĊOžÃƒ·¢i@~c—‡ĝe_«”Eš“}QxgɪëÏÃ@sÅyXoŖ{ô«ŸuX…ê•Îf`œC‚¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘEjcUóº¯Ĩ_ŘÁMª÷Ð¥Oéȇ¿ÖğǤǷÂF҇zÉx[]­Ĥĝ‰œ¦EP}ûƥé¿İƷTėƫœŕƅ™ƱB»Đ±’ēO…¦E–•}‘`cȺrĦáŖuҞª«IJ‡πdƺÏØZƴwʄ¤ĖGЙǂZĶƒèH¶}ÚZצʥĪï|ÇĦMŔ»İĝLj‹ì¥Βœba­¯¥ǕǚkĆŵĦɑĺƯxūД̵nơʃĽá½M»›òmqóŘĝč˾ăC…ćāƿÝɽ©DZŅ¹đ¥˜³ðLrÁ®ɱĕģʼnǻ̋ȥơŻǛȡVï¹Ň۩ûkɗġƁ§ʇė̕ĩũƽō^ƕŠUv£ƁQï“Ƶkŏ½ΉÃŭdzLқʻ«ƭ\\lƒ‡ŭD‡“{ʓDkaFÃÄa“³ŤđÔGRÈƚhSӹŚsİ«ĐË[¥ÚDkº^Øg¼ŵ¸£EÍö•€ůʼnT¡c_‡ËKY‹ƧUśĵ„݃U_©rETÏʜ±OñtYwē¨ƒ{£¨uM³x½şL©Ùá[ÓÐĥ Νtģ¢\\‚ś’nkO›w¥±ƒT»ƷFɯàĩÞáB¹Æ…ÑUw„੍žĽw[“mG½Èå~‡Æ÷QyŠěCFmĭZī—ŵVÁ™ƿQƛ—ûXS²‰b½KϽĉS›©ŷXĕŸ{ŽĕK·¥Ɨcqq©f¿]‡ßDõU³h—­gËÇïģÉɋw“k¯í}I·šœbmœÉ–ř›īJɥĻˁ×xo›ɹī‡l•c…¤³Xù]‘™DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®Ɲv•Um©³G\\“}µĿ‡QyŹl㓛µEw‰LJQ½yƋBe¶ŋÀů‡ož¥A—˜Éw@•{Gpm¿Aij†ŽKLhˆ³`ñcËtW‚±»ÕS‰ëüÿďD‡u\\wwwù³—V›LŕƒOMËGh£õP¡™er™Ïd{“‡ġWÁ…č|yšg^ğyÁzÙs`—s|ÉåªÇ}m¢Ń¨`x¥’ù^•}ƒÌ¥H«‰Yªƅ”Aйn~ź¯šf¤áÀz„gŠÇDIԝ´AňĀ҄¶ûEYospõD[{ù°]u›Jq•U•|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw €ÞkrťË¿XGÉbřaDü·Ē÷Aê[Ää€I®BÕИÞ_¢āĠpŠÛÄȉĖġDKwbm‡ÄNô‡ŠfœƫVÉvi†dz—H‘‹QµâFšù­Âœ³¦{YGžƒd¢ĚÜO „€{Ö¦ÞÍÀPŒ^b–ƾŠlŽ[„vt×ĈÍE˨¡Đ~´î¸ùÎh€uè`¸ŸHÕŔVºwĠââWò‡@{œÙNÝ´ə²ȕn{¿¥{l—÷eé^e’ďˆXj©î\\ªÑò˜Üìc\\üqˆÕ[Č¡xoÂċªbØ­Œø|€¶ȴZdÆšońéŒGš\\”¼C°ÌƁn´nxšÊOĨ’Ūƴĸ¢¸òTxÊǪMīИÖŲÃɎOvˆʦƢ~FŽ‡Rěò—¿ġ~åŊœú‰Nšžš¸qŽ’Ę[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾œĄYÒ©ÊfºmԈĘcDoĬMŬ’˜S¤„s²‚”ʘچžȂVŦ –ŽèW°ªB|IJXŔþÈJĦÆæFĚêŠYĂªĂ]øªŖNÞüA€’fɨJ€˜¯ÎrDDšĤ€`€mz\\„§~D¬{vJÂ˜«lµĂb–¤p€ŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMT”‡òP˜÷fØĶK¢ȝ˔Sô¹òEð­”`Ɩ½ǒÂň×äı–§ĤƝ§C~¡‚hlå‚ǺŦŞkâ’~}ŽFøàIJaĞ‚fƠ¥Ž„Ŕdž˜®U¸ˆźXœv¢aƆúŪtŠųƠjd•ƺŠƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬŠ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹œ\\ĜÑŚŸ¶ZƄ³àjĨoâŠȴLʉȮŒĐ­ĚăŽÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§΢{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTŠiƢ¾ªì°`öøu®Ê¾ãØ" + ], + encodeOffsets: [[88824, 50096]] + }, + properties: { cp: [87.617733, 43.792818], name: "新疆", childNum: 1 } + }, + { + id: "110000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@ĽOÁ›ûtŷmiÍt_H»Ĩ±d`Š¹­{bw…Yr“³S]§§o¹€qGtm_Sŧ€“oa›‹FLg‘QN_•dV€@Zom_ć\\ߚc±x¯oœRcfe…£’o§ËgToÛJíĔóu…|wP¤™XnO¢ÉˆŦ¯rNÄā¤zâŖÈRpŢZŠœÚ{GŠrFt¦Òx§ø¹RóäV¤XdˆżâºWbwŚ¨Ud®bêņ¾‘jnŎGŃŶŠnzÚSeîĜZczî¾i]͜™QaúÍÔiþĩȨWĢ‹ü|Ėu[qb[swP@ÅğP¿{\\‡¥A¨Ï‘Ѩj¯ŠX\\¯œMK‘pA³[H…īu}}" + ], + encodeOffsets: [[120023, 41045]] + }, + properties: { cp: [116.405285, 39.904989], name: "北京", childNum: 1 } + }, + { + id: "120000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: [ + "@@ŬgX§Ü«E…¶Ḟ“¬O_™ïlÁg“z±AXe™µÄĵ{¶]gitgšIj·›¥îakS€‰¨ÐƎk}ĕ{gB—qGf{¿a†U^fI“ư‹³õ{YƒıëNĿžk©ïËZŏ‘R§òoY×Ógc…ĥs¡bġ«@dekąI[nlPqCnp{ˆō³°`{PNdƗqSÄĻNNâyj]äžÒD ĬH°Æ]~¡HO¾ŒX}ÐxŒgp“gWˆrDGˆŒpù‚Š^L‚ˆrzWxˆZ^¨´T\\|~@I‰zƒ–bĤ‹œjeĊªz£®Ĕvě€L†mV¾Ô_ȔNW~zbĬvG†²ZmDM~”~" + ], + encodeOffsets: [[120237, 41215]] + }, + properties: { cp: [117.190182, 39.125596], name: "天津", childNum: 1 } + }, + { + id: "310000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@ɧư¬EpƸÁxc‡"], + ["@@©„ªƒ"], + ["@@”MA‹‘š"], + ["@@Qp݁E§ÉC¾"], + ["@@bŝՕÕEȣÚƥêImɇǦèÜĠŒÚžÃƌÃ͎ó"], + [ + "@@ǜûȬɋŠŭ™×^‰sYŒɍDŋ‘ŽąñCG²«ªč@h–_p¯A{‡oloY€¬j@IJ`•gQڛhr|ǀ^MIJvtbe´R¯Ô¬¨YŽô¤r]ì†Ƭį" + ] + ], + encodeOffsets: [ + [[124702, 32062]], + [[124547, 32200]], + [[124808, 31991]], + [[124726, 32110]], + [[124903, 32376]], + [[124438, 32149]] + ] + }, + properties: { cp: [121.472644, 31.231706], name: "上海", childNum: 6 } + }, + { + id: "500000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + [ + "@@vjG~nGŘŬĶȂƀƾ¹¸ØÎezĆT¸}êЖqHŸðqĖ䒊¥^CƒIj–²p…\\_ æüY|[YxƊæuž°xb®…Űb@~¢NQt°¶‚S栓Ê~rljĔëĚ¢~šuf`‘‚†fa‚ĔJåĊ„nÖ]„jƎćÊ@Š£¾a®£Ű{ŶĕF‹ègLk{Y|¡ĜWƔtƬJÑxq‹±ĢN´‰òK‰™–LÈüD|s`ŋ’ć]ƒÃ‰`đŒMûƱ½~Y°ħ`ƏíW‰½eI‹½{aŸ‘OIrÏ¡ĕŇa†p†µÜƅġ‘œ^ÖÛbÙŽŏml½S‹êqDu[R‹ãË»†ÿw`»y‘¸_ĺę}÷`M¯ċfCVµqʼn÷Z•gg“Œ`d½pDO‡ÎCnœ^uf²ènh¼WtƏxRGg¦…pV„†FI±ŽG^ŒIc´ec‡’G•ĹÞ½sëĬ„h˜xW‚}Kӈe­Xsbk”F¦›L‘ØgTkïƵNï¶}Gy“w\\oñ¡nmĈzjŸ•@™Óc£»Wă¹Ój“_m»ˆ¹·~MvÛaqœ»­‰êœ’\\ÂoVnŽÓØ͙²«‹bq¿efE „€‹Ĝ^Qž~ Évý‡ş¤²Į‰pEİ}zcĺƒL‹½‡š¿gņ›¡ýE¡ya£³t\\¨\\vú»¼§·Ñr_oÒý¥u‚•_n»_ƒ•At©Þűā§IVeëƒY}{VPÀFA¨ąB}q@|Ou—\\Fm‰QF݅Mw˜å}]•€|FmϋCaƒwŒu_p—¯sfÙgY…DHl`{QEfNysBŠ¦zG¸rHe‚„N\\CvEsÐùÜ_·ÖĉsaQ¯€}_U‡†xÃđŠq›NH¬•Äd^ÝŰR¬ã°wećJEž·vÝ·Hgƒ‚éFXjÉê`|yŒpxkAwœWĐpb¥eOsmzwqChóUQl¥F^laf‹anòsr›EvfQdÁUVf—ÎvÜ^efˆtET¬ôA\\œ¢sJŽnQTjP؈xøK|nBz‰„œĞ»LY‚…FDxӄvr“[ehľš•vN”¢o¾NiÂxGp⬐z›bfZo~hGi’]öF|‰|Nb‡tOMn eA±ŠtPT‡LjpYQ|†SH††YĀxinzDJ€Ìg¢và¥Pg‰_–ÇzII‹€II•„£®S¬„Øs쐣ŒN" + ], + ["@@ifjN@s"] + ], + encodeOffsets: [[[109628, 30765]], [[111725, 31320]]] + }, + properties: { cp: [106.504962, 29.533155], name: "重庆", childNum: 2 } + }, + { + id: "810000", + type: "Feature", + geometry: { + type: "MultiPolygon", + coordinates: [ + ["@@AlBk"], + ["@@mŽn"], + ["@@EpFo"], + [ + "@@ea¢pl¸Eõ¹‡hj[ƒ]ÔCΖ@lj˜¡uBXŸ…•´‹AI¹…[‹yDUˆ]W`çwZkmc–…M›žp€Åv›}I‹oJlcaƒfёKŽ°ä¬XJmРđhI®æÔtSHn€Eˆ„ÒrÈc" + ], + ["@@rMUw‡AS®€e"] + ], + encodeOffsets: [ + [[117111, 23002]], + [[117072, 22876]], + [[117045, 22887]], + [[116975, 23082]], + [[116882, 22747]] + ] + }, + properties: { cp: [114.173355, 22.320048], name: "香港", childNum: 5 } + }, + { + id: "820000", + type: "Feature", + geometry: { + type: "Polygon", + coordinates: ["@@kÊd°å§s"], + encodeOffsets: [[116279, 22639]] + }, + properties: { cp: [113.54909, 22.198951], name: "澳门", childNum: 1 } + } + ], + UTF8Encoding: true + }); +}); diff --git a/zhi-admin-ui/src/assets/js/config.js b/zhi-admin-ui/src/assets/js/config.js new file mode 100644 index 0000000..ce25e62 --- /dev/null +++ b/zhi-admin-ui/src/assets/js/config.js @@ -0,0 +1,4 @@ +export default { + TENCENT_CAPTCHA: "2088053498", + UPLOAD_SIZE: 200 // 压缩文件大小 +}; diff --git a/zhi-admin-ui/src/assets/js/emoji.js b/zhi-admin-ui/src/assets/js/emoji.js new file mode 100644 index 0000000..70b415d --- /dev/null +++ b/zhi-admin-ui/src/assets/js/emoji.js @@ -0,0 +1,115 @@ +export default { + "[微笑]": "😀", + + "[笑]": " https://static.talkxj.com/emoji/dx.jpg", + + "[呲牙]": "https://static.talkxj.com/emoji/cy.jpg", + + "[OK]": "https://static.talkxj.com/emoji/ok.jpg", + + "[星星眼]": "https://static.talkxj.com/emoji/xxy.jpg", + + "[哦呼]": "https://static.talkxj.com/emoji/oh.jpg", + + "[嫌弃]": "https://static.talkxj.com/emoji/xq.jpg", + + "[喜欢]": "https://static.talkxj.com/emoji/xh.jpg", + + "[酸了]": "https://static.talkxj.com/emoji/sl.jpg", + + "[大哭]": "https://static.talkxj.com/emoji/dq.jpg?", + + "[害羞]": "https://static.talkxj.com/emoji/hx.jpg", + + "[无语]": "https://static.talkxj.com/emoji/wy.jpg", + + "[疑惑]": "https://static.talkxj.com/emoji/yh.jpg", + + "[调皮]": "https://static.talkxj.com/emoji/tiaopi.jpg", + + "[笑哭]": "https://static.talkxj.com/emoji/xiaoku.jpg", + + "[奸笑]": "https://static.talkxj.com/emoji/jianxiao.jpg", + + "[偷笑]": "https://static.talkxj.com/emoji/touxiao.jpg", + + "[大笑]": "https://static.talkxj.com/emoji/daxiao.jpg", + + "[阴险]": "https://static.talkxj.com/emoji/yinxian.jpg", + + "[捂脸]": "https://static.talkxj.com/emoji/wulian.jpg", + + "[呆]": "https://static.talkxj.com/emoji/dai.jpg", + + "[抠鼻]": "https://static.talkxj.com/emoji/koubi.jpg", + + "[惊喜]": "https://static.talkxj.com/emoji/jingxi.jpg", + + "[惊讶]": "https://static.talkxj.com/emoji/jingya.jpg", + + "[捂脸哭]": "https://static.talkxj.com/emoji/wulianku.jpg", + + "[妙啊]": "https://static.talkxj.com/emoji/miaoa.jpg", + + "[狗头]": "https://static.talkxj.com/emoji/goutou.jpg", + + "[滑稽]": "https://static.talkxj.com/emoji/huaji.jpg", + + "[吃瓜]": "https://static.talkxj.com/emoji/chigua.jpg", + + "[打call]": "https://static.talkxj.com/emoji/dacall.jpg", + + "[点赞]": "https://static.talkxj.com/emoji/dianzan.jpg", + + "[鼓掌]": "https://static.talkxj.com/emoji/guzhang.jpg", + + "[尴尬]": "https://static.talkxj.com/emoji/ganga.jpg", + + "[冷]": "https://static.talkxj.com/emoji/leng.jpg", + + "[灵魂出窍]": "https://static.talkxj.com/emoji/linghunchuqiao.jpg", + + "[委屈]": "https://static.talkxj.com/emoji/weiqu.jpg", + + "[傲娇]": "https://static.talkxj.com/emoji/aojiao.jpg", + + "[疼]": "https://static.talkxj.com/emoji/teng.jpg", + + "[吓]": "https://static.talkxj.com/emoji/xia.jpg?", + + "[生病]": "https://static.talkxj.com/emoji/shengbing.jpg", + + "[吐]": "https://static.talkxj.com/emoji/tu.jpg", + + "[嘘声]": "https://static.talkxj.com/emoji/xusheng.jpg", + + "[捂眼]": "https://static.talkxj.com/emoji/wuyan.jpg", + + "[思考]": "https://static.talkxj.com/emoji/sikao.jpg", + + "[再见]": "https://static.talkxj.com/emoji/zaijian.jpg", + + "[翻白眼]": "https://static.talkxj.com/emoji/fanbaiyan.jpg", + + "[哈欠]": "https://static.talkxj.com/emoji/haqian.jpg", + + "[奋斗]": "https://static.talkxj.com/emoji/fengdou.jpg", + + "[墨镜]": "https://static.talkxj.com/emoji/mojing.jpg", + + "[撇嘴]": "https://static.talkxj.com/emoji/piezui.jpg", + + "[难过]": "https://static.talkxj.com/emoji/nanguo.jpg", + + "[抓狂]": "https://static.talkxj.com/emoji/zhuakuang.jpg", + + "[生气]": "https://static.talkxj.com/emoji/shengqi.jpg", + + "[爱心]": "https://static.talkxj.com/emoji/aixin.jpg", + + "[胜利]": "https://static.talkxj.com/emoji/shengli.jpg", + + "[保佑]": "https://static.talkxj.com/emoji/baoyou.jpg", + + "[支持]": "https://static.talkxj.com/emoji/zhichi.jpg" +}; diff --git a/zhi-admin-ui/src/assets/js/menu.js b/zhi-admin-ui/src/assets/js/menu.js new file mode 100644 index 0000000..560e06c --- /dev/null +++ b/zhi-admin-ui/src/assets/js/menu.js @@ -0,0 +1,41 @@ +import Layout from "@/layout/index.vue"; +import router from "../../router"; +import store from "../../store"; +import axios from "axios"; +import Vue from "vue"; + +export function generaMenu() { + // 查询用户菜单 + axios.get("/api/admin/user/menus").then(({ data }) => { + if (data.flag) { + var userMenuList = data.data; + userMenuList.forEach((item) => { + if (item.icon != null) { + item.icon = "iconfont " + item.icon; + } + if (item.component == "Layout") { + item.component = Layout; + } + if (item.children && item.children.length > 0) { + item.children.forEach((route) => { + route.icon = "iconfont " + route.icon; + route.component = loadView(route.component); + }); + } + }); + // 添加侧边栏菜单 + store.commit("saveUserMenuList", userMenuList); + // 添加菜单到路由 + //@ts-ignore + router.addRoutes(userMenuList); + } else { + Vue.prototype.$message.error(data.message); + router.push({ path: "/login" }); + } + }); +} + +export const loadView = (view) => { + // 路由懒加载 + return (resolve) => require([`@/views${view}`], resolve); +}; diff --git a/zhi-admin-ui/src/assets/js/newEmoji.js b/zhi-admin-ui/src/assets/js/newEmoji.js new file mode 100644 index 0000000..647dc64 --- /dev/null +++ b/zhi-admin-ui/src/assets/js/newEmoji.js @@ -0,0 +1,75 @@ +export default { + "[微笑]": "🙂", + + "[笑]": "😃", + + "[大笑]": "😄 ", + + "[嘻嘻]": "😁", + + "[斜眼笑]": "😆", + + "[苦笑]": "😅", + + "[笑出泪]": "🤣", + + "[眨眼]": "😉", + + "[喜笑颜开]": "🥰", + + "[花痴]": "😍", + + "[崇拜]": "🤩", + + "[飞吻]": "😘", + + "[亲亲]": "😗", + + "[羞涩]": "😚", + + "[好吃]": "😋", + + "[吐舌]": "😛", + + "[滑稽]": "🤪", + + "[挑眉]": "🤨", + + "[不高兴]": "😒", + + "[流口水]": "🤤", + + "[睡着]": "😴", + + "[感冒]": "😷", + + "[受伤]": "🤕", + + "[冷脸]": "🥶", + + "[头晕]": "😵", + + "[墨镜笑]": "😎", + + "[震惊]": "😲", + + "[累]": "😫", + + "[生气]": "😡", + + "[小丑]": "🤡", + + "[机器人]": "🤖", + + "[爱心]": "💗", + + "[中箭心]": "💘", + + "[情书]": "💌", + + "[一百分]": "💯", + + "[爆炸]": "💥", + + "[汗滴]": "💦", +}; diff --git a/zhi-admin-ui/src/assets/logo/logo.png b/zhi-admin-ui/src/assets/logo/logo.png new file mode 100644 index 0000000..cdd1a7d Binary files /dev/null and b/zhi-admin-ui/src/assets/logo/logo.png differ diff --git a/zhi-admin-ui/src/assets/styles/btn.scss b/zhi-admin-ui/src/assets/styles/btn.scss new file mode 100644 index 0000000..e6ba1a8 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/btn.scss @@ -0,0 +1,99 @@ +@import './variables.scss'; + +@mixin colorBtn($color) { + background: $color; + + &:hover { + color: $color; + + &:before, + &:after { + background: $color; + } + } +} + +.blue-btn { + @include colorBtn($blue) +} + +.light-blue-btn { + @include colorBtn($light-blue) +} + +.red-btn { + @include colorBtn($red) +} + +.pink-btn { + @include colorBtn($pink) +} + +.green-btn { + @include colorBtn($green) +} + +.tiffany-btn { + @include colorBtn($tiffany) +} + +.yellow-btn { + @include colorBtn($yellow) +} + +.pan-btn { + font-size: 14px; + color: #fff; + padding: 14px 36px; + border-radius: 8px; + border: none; + outline: none; + transition: 600ms ease all; + position: relative; + display: inline-block; + + &:hover { + background: #fff; + + &:before, + &:after { + width: 100%; + transition: 600ms ease all; + } + } + + &:before, + &:after { + content: ''; + position: absolute; + top: 0; + right: 0; + height: 2px; + width: 0; + transition: 400ms ease all; + } + + &::after { + right: inherit; + top: inherit; + left: 0; + bottom: 0; + } +} + +.custom-button { + display: inline-block; + line-height: 1; + white-space: nowrap; + cursor: pointer; + background: #fff; + color: #fff; + -webkit-appearance: none; + text-align: center; + box-sizing: border-box; + outline: 0; + margin: 0; + padding: 10px 15px; + font-size: 14px; + border-radius: 4px; +} diff --git a/zhi-admin-ui/src/assets/styles/element-ui.scss b/zhi-admin-ui/src/assets/styles/element-ui.scss new file mode 100644 index 0000000..363092a --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/element-ui.scss @@ -0,0 +1,92 @@ +// cover some element-ui styles + +.el-breadcrumb__inner, +.el-breadcrumb__inner a { + font-weight: 400 !important; +} + +.el-upload { + input[type="file"] { + display: none !important; + } +} + +.el-upload__input { + display: none; +} + +.cell { + .el-tag { + margin-right: 0px; + } +} + +.small-padding { + .cell { + padding-left: 5px; + padding-right: 5px; + } +} + +.fixed-width { + .el-button--mini { + padding: 7px 10px; + width: 60px; + } +} + +.status-col { + .cell { + padding: 0 10px; + text-align: center; + + .el-tag { + margin-right: 0px; + } + } +} + +// to fixed https://github.com/ElemeFE/element/issues/2461 +.el-dialog { + transform: none; + left: 0; + position: relative; + margin: 0 auto; +} + +// refine element ui upload +.upload-container { + .el-upload { + width: 100%; + + .el-upload-dragger { + width: 100%; + height: 200px; + } + } +} + +// dropdown +.el-dropdown-menu { + a { + display: block + } +} + +// fix date-picker ui bug in filter-item +.el-range-editor.el-input__inner { + display: inline-flex !important; +} + +// to fix el-date-picker css style +.el-range-separator { + box-sizing: content-box; +} + +.el-menu--collapse + > div + > .el-submenu + > .el-submenu__title + .el-submenu__icon-arrow { + display: none; +} \ No newline at end of file diff --git a/zhi-admin-ui/src/assets/styles/element-variables.scss b/zhi-admin-ui/src/assets/styles/element-variables.scss new file mode 100644 index 0000000..1615ff2 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/element-variables.scss @@ -0,0 +1,31 @@ +/** +* I think element-ui's default theme color is too light for long-term use. +* So I modified the default color and you can modify it to your liking. +**/ + +/* theme color */ +$--color-primary: #1890ff; +$--color-success: #13ce66; +$--color-warning: #ffba00; +$--color-danger: #ff4949; +// $--color-info: #1E1E1E; + +$--button-font-weight: 400; + +// $--color-text-regular: #1f2d3d; + +$--border-color-light: #dfe4ed; +$--border-color-lighter: #e6ebf5; + +$--table-border: 1px solid #dfe6ec; + +/* icon font path, required */ +$--font-path: '~element-ui/lib/theme-chalk/fonts'; + +@import "~element-ui/packages/theme-chalk/src/index"; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + theme: $--color-primary; +} diff --git a/zhi-admin-ui/src/assets/styles/index.scss b/zhi-admin-ui/src/assets/styles/index.scss new file mode 100644 index 0000000..96095ef --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/index.scss @@ -0,0 +1,191 @@ +@import './variables.scss'; +@import './mixin.scss'; +@import './transition.scss'; +@import './element-ui.scss'; +@import './sidebar.scss'; +@import './btn.scss'; + +body { + height: 100%; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; +} + +label { + font-weight: 700; +} + +html { + height: 100%; + box-sizing: border-box; +} + +#app { + height: 100%; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +.no-padding { + padding: 0px !important; +} + +.padding-content { + padding: 4px 0; +} + +a:focus, +a:active { + outline: none; +} + +a, +a:focus, +a:hover { + cursor: pointer; + color: inherit; + text-decoration: none; +} + +div:focus { + outline: none; +} + +.fr { + float: right; +} + +.fl { + float: left; +} + +.pr-5 { + padding-right: 5px; +} + +.pl-5 { + padding-left: 5px; +} + +.block { + display: block; +} + +.pointer { + cursor: pointer; +} + +.inlineBlock { + display: block; +} + +.clearfix { + &:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; + } +} + +aside { + background: #eef1f6; + padding: 8px 24px; + margin-bottom: 20px; + border-radius: 2px; + display: block; + line-height: 32px; + font-size: 16px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + color: #2c3e50; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + a { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } + } +} + +//main-container全局样式 +.app-container { + padding: 20px; +} + +.components-container { + margin: 30px 50px; + position: relative; +} + +.pagination-container { + margin-top: 30px; +} + +.text-center { + text-align: center +} + +.sub-navbar { + height: 50px; + line-height: 50px; + position: relative; + width: 100%; + text-align: right; + padding-right: 20px; + transition: 600ms ease position; + background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); + + .subtitle { + font-size: 20px; + color: #fff; + } + + &.draft { + background: #d0d0d0; + } + + &.deleted { + background: #d0d0d0; + } +} + +.link-type, +.link-type:focus { + color: #337ab7; + cursor: pointer; + + &:hover { + color: rgb(32, 160, 255); + } +} + +.filter-container { + padding-bottom: 10px; + + .filter-item { + display: inline-block; + vertical-align: middle; + margin-bottom: 10px; + } +} + +//refine vue-multiselect plugin +.multiselect { + line-height: 16px; +} + +.multiselect--active { + z-index: 1000 !important; +} diff --git a/zhi-admin-ui/src/assets/styles/mixin.scss b/zhi-admin-ui/src/assets/styles/mixin.scss new file mode 100644 index 0000000..06fa061 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/mixin.scss @@ -0,0 +1,66 @@ +@mixin clearfix { + &:after { + content: ""; + display: table; + clear: both; + } +} + +@mixin scrollBar { + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } +} + +@mixin relative { + position: relative; + width: 100%; + height: 100%; +} + +@mixin pct($pct) { + width: #{$pct}; + position: relative; + margin: 0 auto; +} + +@mixin triangle($width, $height, $color, $direction) { + $width: $width/2; + $color-border-style: $height solid $color; + $transparent-border-style: $width solid transparent; + height: 0; + width: 0; + + @if $direction==up { + border-bottom: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==right { + border-left: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } + + @else if $direction==down { + border-top: $color-border-style; + border-left: $transparent-border-style; + border-right: $transparent-border-style; + } + + @else if $direction==left { + border-right: $color-border-style; + border-top: $transparent-border-style; + border-bottom: $transparent-border-style; + } +} diff --git a/zhi-admin-ui/src/assets/styles/ruoyi.scss b/zhi-admin-ui/src/assets/styles/ruoyi.scss new file mode 100644 index 0000000..16a4740 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/ruoyi.scss @@ -0,0 +1,287 @@ +/** +* 通用css样式布局处理 +* Copyright (c) 2019 ruoyi +*/ + +/** 基础通用 **/ +.pt5 { + padding-top: 5px; +} + +.pr5 { + padding-right: 5px; +} + +.pb5 { + padding-bottom: 5px; +} + +.mt5 { + margin-top: 5px; +} + +.mr5 { + margin-right: 5px; +} + +.mb5 { + margin-bottom: 5px; +} + +.mb8 { + margin-bottom: 8px; +} + +.ml5 { + margin-left: 5px; +} + +.mt10 { + margin-top: 10px; +} + +.mr10 { + margin-right: 10px; +} + +.mb10 { + margin-bottom: 10px; +} +.ml10 { + margin-left: 10px; +} + +.mt20 { + margin-top: 20px; +} + +.mr20 { + margin-right: 20px; +} + +.mb20 { + margin-bottom: 20px; +} +.ml20 { + 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; +} + +.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body { + overflow: auto; + overflow-x: hidden; + max-height: 70vh; + padding: 10px 20px 0; +} + +.el-table { + .el-table__header-wrapper, .el-table__fixed-header-wrapper { + th { + word-break: break-word; + background-color: #f8f8f9; + color: #515a6e; + height: 40px; + font-size: 13px; + } + } + + .el-table__body-wrapper { + .el-button [class*="el-icon-"] + span { + margin-left: 1px; + } + } +} + +/** 表单布局 **/ +.form-header { + font-size: 15px; + color: #6379bb; + border-bottom: 1px solid #ddd; + margin: 8px 10px 25px 10px; + padding-bottom: 5px +} + +/** 表格布局 **/ +.pagination-container { + position: relative; + height: 25px; + margin-bottom: 10px; + margin-top: 15px; + padding: 10px 20px !important; +} + +/* tree border */ +.tree-border { + margin-top: 5px; + border: 1px solid #e5e6e7; + background: #FFFFFF none; + border-radius: 4px; +} + +.pagination-container .el-pagination { + right: 0; + position: absolute; +} + +@media (max-width: 768px) { + .pagination-container .el-pagination > .el-pagination__jump { + display: none !important; + } + .pagination-container .el-pagination > .el-pagination__sizes { + display: none !important; + } +} + +.el-table .fixed-width .el-button--mini { + padding-left: 0; + padding-right: 0; + width: inherit; +} + +/** 表格更多操作下拉样式 */ +.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine { + cursor: pointer; + margin-left: 5px; +} + +.el-table .el-dropdown, .el-icon-arrow-down { + font-size: 12px; +} + +.el-tree-node__content > .el-checkbox { + margin-right: 8px; +} + +.list-group-striped > .list-group-item { + border-left: 0; + border-right: 0; + border-radius: 0; + padding-left: 0; + padding-right: 0; +} + +.list-group { + padding-left: 0px; + list-style: none; +} + +.list-group-item { + border-bottom: 1px solid #e7eaec; + border-top: 1px solid #e7eaec; + margin-bottom: -1px; + padding: 11px 0px; + font-size: 13px; +} + +.pull-right { + float: right !important; +} + +.el-card__header { + padding: 14px 15px 7px; + min-height: 40px; +} + +.el-card__body { + padding: 15px 20px 20px 20px; +} + +.card-box { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 10px; +} + +/* button color */ +.el-button--cyan.is-active, +.el-button--cyan:active { + background: #20B2AA; + border-color: #20B2AA; + color: #FFFFFF; +} + +.el-button--cyan:focus, +.el-button--cyan:hover { + background: #48D1CC; + border-color: #48D1CC; + color: #FFFFFF; +} + +.el-button--cyan { + background-color: #20B2AA; + border-color: #20B2AA; + color: #FFFFFF; +} + +/* text color */ +.text-navy { + color: #1ab394; +} + +.text-primary { + color: inherit; +} + +.text-success { + color: #1c84c6; +} + +.text-info { + color: #23c6c8; +} + +.text-warning { + color: #f8ac59; +} + +.text-danger { + color: #ed5565; +} + +.text-muted { + color: #888888; +} + +/* image */ +.img-circle { + border-radius: 50%; +} + +.img-lg { + width: 120px; + height: 120px; +} + +.avatar-upload-preview { + position: relative; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 200px; + height: 200px; + border-radius: 50%; + box-shadow: 0 0 4px #ccc; + overflow: hidden; +} + +/* 拖拽列样式 */ +.sortable-ghost { + opacity: .8; + color: #fff !important; + background: #42b983 !important; +} + +.top-right-btn { + position: relative; + float: right; +} diff --git a/zhi-admin-ui/src/assets/styles/sidebar.scss b/zhi-admin-ui/src/assets/styles/sidebar.scss new file mode 100644 index 0000000..ed308b8 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/sidebar.scss @@ -0,0 +1,227 @@ +#app { + + .main-container { + min-height: 100%; + transition: margin-left .28s; + margin-left: $base-sidebar-width; + position: relative; + } + + .sidebarHide { + margin-left: 0!important; + } + + .sidebar-container { + -webkit-transition: width .28s; + transition: width 0.28s; + width: $base-sidebar-width !important; + background-color: $base-menu-background; + height: 100%; + position: fixed; + font-size: 0px; + top: 0; + bottom: 0; + left: 0; + z-index: 1001; + overflow: hidden; + -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); + box-shadow: 2px 0 6px rgba(0,21,41,.35); + + // reset element-ui css + .horizontal-collapse-transition { + transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; + } + + .scrollbar-wrapper { + overflow-x: hidden !important; + } + + .el-scrollbar__bar.is-vertical { + right: 0px; + } + + .el-scrollbar { + height: 100%; + } + + &.has-logo { + .el-scrollbar { + height: calc(100% - 50px); + } + } + + .is-horizontal { + display: none; + } + + a { + display: inline-block; + width: 100%; + overflow: hidden; + } + + .svg-icon { + margin-right: 16px; + } + + .el-menu { + border: none; + height: 100%; + width: 100% !important; + } + + .el-menu-item, .el-submenu__title { + overflow: hidden !important; + text-overflow: ellipsis !important; + white-space: nowrap !important; + } + + // menu hover + .submenu-title-noDropdown, + .el-submenu__title { + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .is-active > .el-submenu__title { + color: $base-menu-color-active !important; + } + + & .nest-menu .el-submenu>.el-submenu__title, + & .el-submenu .el-menu-item { + min-width: $base-sidebar-width !important; + + &:hover { + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + & .theme-dark .nest-menu .el-submenu>.el-submenu__title, + & .theme-dark .el-submenu .el-menu-item { + background-color: $base-sub-menu-background !important; + + &:hover { + background-color: $base-sub-menu-hover !important; + } + } + } + + .hideSidebar { + .sidebar-container { + width: 54px !important; + } + + .main-container { + margin-left: 54px; + } + + .submenu-title-noDropdown { + padding: 0 !important; + position: relative; + + .el-tooltip { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + } + } + + .el-submenu { + overflow: hidden; + + &>.el-submenu__title { + padding: 0 !important; + + .svg-icon { + margin-left: 20px; + } + + } + } + + .el-menu--collapse { + .el-submenu { + &>.el-submenu__title { + &>span { + height: 0; + width: 0; + overflow: hidden; + visibility: hidden; + display: inline-block; + } + } + } + } + } + + .el-menu--collapse .el-menu .el-submenu { + min-width: $base-sidebar-width !important; + } + + // mobile responsive + .mobile { + .main-container { + margin-left: 0px; + } + + .sidebar-container { + transition: transform .28s; + width: $base-sidebar-width !important; + } + + &.hideSidebar { + .sidebar-container { + pointer-events: none; + transition-duration: 0.3s; + transform: translate3d(-$base-sidebar-width, 0, 0); + } + } + } + + .withoutAnimation { + + .main-container, + .sidebar-container { + transition: none; + } + } +} + +// when menu collapsed +.el-menu--vertical { + &>.el-menu { + .svg-icon { + margin-right: 16px; + } + } + + .nest-menu .el-submenu>.el-submenu__title, + .el-menu-item { + &:hover { + // you can use $subMenuHover + background-color: rgba(0, 0, 0, 0.06) !important; + } + } + + // the scroll bar appears when the subMenu is too long + >.el-menu--popup { + max-height: 100vh; + overflow-y: auto; + + &::-webkit-scrollbar-track-piece { + background: #d3dce6; + } + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-thumb { + background: #99a9bf; + border-radius: 20px; + } + } +} diff --git a/zhi-admin-ui/src/assets/styles/transition.scss b/zhi-admin-ui/src/assets/styles/transition.scss new file mode 100644 index 0000000..eb49895 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/transition.scss @@ -0,0 +1,53 @@ +// global transition css + +/* fade */ +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.28s; +} + +.fade-enter, +.fade-leave-active { + opacity: 0; +} + +/* fade-transform */ +.fade-transform--move, +.fade-transform-leave-active, +.fade-transform-enter-active { + transition: all .5s; +} + +.fade-transform-leave-active { + position: absolute; +} + +.fade-transform-enter { + opacity: 0; + transform: translateX(-30px); +} + +.fade-transform-leave-to { + opacity: 0; + transform: translateX(30px); +} + +/* breadcrumb transition */ +.breadcrumb-enter-active, +.breadcrumb-leave-active { + transition: all .5s; +} + +.breadcrumb-enter, +.breadcrumb-leave-active { + opacity: 0; + transform: translateX(20px); +} + +.breadcrumb-move { + transition: all .5s; +} + +.breadcrumb-leave-active { + position: absolute; +} diff --git a/zhi-admin-ui/src/assets/styles/variables.scss b/zhi-admin-ui/src/assets/styles/variables.scss new file mode 100644 index 0000000..34484d4 --- /dev/null +++ b/zhi-admin-ui/src/assets/styles/variables.scss @@ -0,0 +1,54 @@ +// base color +$blue:#324157; +$light-blue:#3A71A8; +$red:#C03639; +$pink: #E65D6E; +$green: #30B08F; +$tiffany: #4AB7BD; +$yellow:#FEC171; +$panGreen: #30B08F; + +// 默认菜单主题风格 +$base-menu-color:#bfcbd9; +$base-menu-color-active:#f4f4f5; +$base-menu-background:#304156; +$base-logo-title-color: #ffffff; + +$base-menu-light-color:rgba(0,0,0,.70); +$base-menu-light-background:#ffffff; +$base-logo-light-title-color: #001529; + +$base-sub-menu-background:#1f2d3d; +$base-sub-menu-hover:#001528; + +// 自定义暗色菜单风格 +/** +$base-menu-color:hsla(0,0%,100%,.65); +$base-menu-color-active:#fff; +$base-menu-background:#001529; +$base-logo-title-color: #ffffff; + +$base-menu-light-color:rgba(0,0,0,.70); +$base-menu-light-background:#ffffff; +$base-logo-light-title-color: #001529; + +$base-sub-menu-background:#000c17; +$base-sub-menu-hover:#001528; +*/ + +$base-sidebar-width: 200px; + +// the :export directive is the magic sauce for webpack +// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass +:export { + menuColor: $base-menu-color; + menuLightColor: $base-menu-light-color; + menuColorActive: $base-menu-color-active; + menuBackground: $base-menu-background; + menuLightBackground: $base-menu-light-background; + subMenuBackground: $base-sub-menu-background; + subMenuHover: $base-sub-menu-hover; + sideBarWidth: $base-sidebar-width; + logoTitleColor: $base-logo-title-color; + logoLightTitleColor: $base-logo-light-title-color +} diff --git a/zhi-admin-ui/src/components/Breadcrumb/index.vue b/zhi-admin-ui/src/components/Breadcrumb/index.vue new file mode 100644 index 0000000..1696f54 --- /dev/null +++ b/zhi-admin-ui/src/components/Breadcrumb/index.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/zhi-admin-ui/src/components/Crontab/day.vue b/zhi-admin-ui/src/components/Crontab/day.vue new file mode 100644 index 0000000..fe3eaf0 --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/day.vue @@ -0,0 +1,161 @@ + + + diff --git a/zhi-admin-ui/src/components/Crontab/hour.vue b/zhi-admin-ui/src/components/Crontab/hour.vue new file mode 100644 index 0000000..4b1f1fc --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/hour.vue @@ -0,0 +1,114 @@ + + + diff --git a/zhi-admin-ui/src/components/Crontab/index.vue b/zhi-admin-ui/src/components/Crontab/index.vue new file mode 100644 index 0000000..3963df2 --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/index.vue @@ -0,0 +1,430 @@ + + + + diff --git a/zhi-admin-ui/src/components/Crontab/min.vue b/zhi-admin-ui/src/components/Crontab/min.vue new file mode 100644 index 0000000..43cab90 --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/min.vue @@ -0,0 +1,116 @@ + + + \ No newline at end of file diff --git a/zhi-admin-ui/src/components/Crontab/month.vue b/zhi-admin-ui/src/components/Crontab/month.vue new file mode 100644 index 0000000..fd0ac38 --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/month.vue @@ -0,0 +1,114 @@ + + + diff --git a/zhi-admin-ui/src/components/Crontab/result.vue b/zhi-admin-ui/src/components/Crontab/result.vue new file mode 100644 index 0000000..aea6e0e --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/result.vue @@ -0,0 +1,559 @@ + + + diff --git a/zhi-admin-ui/src/components/Crontab/second.vue b/zhi-admin-ui/src/components/Crontab/second.vue new file mode 100644 index 0000000..e7b7761 --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/second.vue @@ -0,0 +1,117 @@ + + + diff --git a/zhi-admin-ui/src/components/Crontab/week.vue b/zhi-admin-ui/src/components/Crontab/week.vue new file mode 100644 index 0000000..1cec700 --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/week.vue @@ -0,0 +1,202 @@ + + + diff --git a/zhi-admin-ui/src/components/Crontab/year.vue b/zhi-admin-ui/src/components/Crontab/year.vue new file mode 100644 index 0000000..5487a6c --- /dev/null +++ b/zhi-admin-ui/src/components/Crontab/year.vue @@ -0,0 +1,131 @@ + + + diff --git a/zhi-admin-ui/src/components/DictData/index.js b/zhi-admin-ui/src/components/DictData/index.js new file mode 100644 index 0000000..7b85d4a --- /dev/null +++ b/zhi-admin-ui/src/components/DictData/index.js @@ -0,0 +1,49 @@ +import Vue from 'vue' +import store from '@/store' +import DataDict from '@/utils/dict' +import { getDicts as getDicts } from '@/api/system/dict/data' + +function searchDictByKey(dict, key) { + if (key == null && key == "") { + return null + } + try { + for (let i = 0; i < dict.length; i++) { + if (dict[i].key == key) { + return dict[i].value + } + } + } catch (e) { + return null + } +} + +function install() { + Vue.use(DataDict, { + metas: { + '*': { + labelField: 'dictLabel', + valueField: 'dictValue', + request(dictMeta) { + const storeDict = searchDictByKey(store.getters.dict, dictMeta.type) + if (storeDict) { + return new Promise(resolve => { resolve(storeDict) }) + } else { + return new Promise((resolve, reject) => { + getDicts(dictMeta.type).then(res => { + store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data }) + resolve(res.data) + }).catch(error => { + reject(error) + }) + }) + } + }, + }, + }, + }) +} + +export default { + install, +} \ No newline at end of file diff --git a/zhi-admin-ui/src/components/DictTag/index.vue b/zhi-admin-ui/src/components/DictTag/index.vue new file mode 100644 index 0000000..4c196c4 --- /dev/null +++ b/zhi-admin-ui/src/components/DictTag/index.vue @@ -0,0 +1,52 @@ + + + + \ No newline at end of file diff --git a/zhi-admin-ui/src/components/Editor/index.vue b/zhi-admin-ui/src/components/Editor/index.vue new file mode 100644 index 0000000..1f2e15e --- /dev/null +++ b/zhi-admin-ui/src/components/Editor/index.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/zhi-admin-ui/src/components/EditorTwo/Editor.vue b/zhi-admin-ui/src/components/EditorTwo/Editor.vue new file mode 100644 index 0000000..4c95f23 --- /dev/null +++ b/zhi-admin-ui/src/components/EditorTwo/Editor.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/zhi-admin-ui/src/components/FileUpload/index.vue b/zhi-admin-ui/src/components/FileUpload/index.vue new file mode 100644 index 0000000..2e33c1b --- /dev/null +++ b/zhi-admin-ui/src/components/FileUpload/index.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/zhi-admin-ui/src/components/Hamburger/index.vue b/zhi-admin-ui/src/components/Hamburger/index.vue new file mode 100644 index 0000000..368b002 --- /dev/null +++ b/zhi-admin-ui/src/components/Hamburger/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/zhi-admin-ui/src/components/HeaderSearch/index.vue b/zhi-admin-ui/src/components/HeaderSearch/index.vue new file mode 100644 index 0000000..c44eff5 --- /dev/null +++ b/zhi-admin-ui/src/components/HeaderSearch/index.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/zhi-admin-ui/src/components/IconSelect/index.vue b/zhi-admin-ui/src/components/IconSelect/index.vue new file mode 100644 index 0000000..b0ec9fa --- /dev/null +++ b/zhi-admin-ui/src/components/IconSelect/index.vue @@ -0,0 +1,68 @@ + + + + + + diff --git a/zhi-admin-ui/src/components/IconSelect/requireIcons.js b/zhi-admin-ui/src/components/IconSelect/requireIcons.js new file mode 100644 index 0000000..99e5c54 --- /dev/null +++ b/zhi-admin-ui/src/components/IconSelect/requireIcons.js @@ -0,0 +1,11 @@ + +const req = require.context('../../assets/icons/svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys() + +const re = /\.\/(.*)\.svg/ + +const icons = requireAll(req).map(i => { + return i.match(re)[1] +}) + +export default icons diff --git a/zhi-admin-ui/src/components/ImagePreview/index.vue b/zhi-admin-ui/src/components/ImagePreview/index.vue new file mode 100644 index 0000000..cd99626 --- /dev/null +++ b/zhi-admin-ui/src/components/ImagePreview/index.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/zhi-admin-ui/src/components/ImageUpload/index.vue b/zhi-admin-ui/src/components/ImageUpload/index.vue new file mode 100644 index 0000000..9c92e86 --- /dev/null +++ b/zhi-admin-ui/src/components/ImageUpload/index.vue @@ -0,0 +1,231 @@ + + + + + diff --git a/zhi-admin-ui/src/components/Pagination/index.vue b/zhi-admin-ui/src/components/Pagination/index.vue new file mode 100644 index 0000000..56f5a6b --- /dev/null +++ b/zhi-admin-ui/src/components/Pagination/index.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/zhi-admin-ui/src/components/PanThumb/index.vue b/zhi-admin-ui/src/components/PanThumb/index.vue new file mode 100644 index 0000000..1bcf417 --- /dev/null +++ b/zhi-admin-ui/src/components/PanThumb/index.vue @@ -0,0 +1,142 @@ + + + + + diff --git a/zhi-admin-ui/src/components/ParentView/index.vue b/zhi-admin-ui/src/components/ParentView/index.vue new file mode 100644 index 0000000..7bf6148 --- /dev/null +++ b/zhi-admin-ui/src/components/ParentView/index.vue @@ -0,0 +1,3 @@ + diff --git a/zhi-admin-ui/src/components/RightPanel/index.vue b/zhi-admin-ui/src/components/RightPanel/index.vue new file mode 100644 index 0000000..2d6122b --- /dev/null +++ b/zhi-admin-ui/src/components/RightPanel/index.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/zhi-admin-ui/src/components/RightToolbar/index.vue b/zhi-admin-ui/src/components/RightToolbar/index.vue new file mode 100644 index 0000000..527e07c --- /dev/null +++ b/zhi-admin-ui/src/components/RightToolbar/index.vue @@ -0,0 +1,104 @@ + + + diff --git a/zhi-admin-ui/src/components/RuoYi/Doc/index.vue b/zhi-admin-ui/src/components/RuoYi/Doc/index.vue new file mode 100644 index 0000000..348ca30 --- /dev/null +++ b/zhi-admin-ui/src/components/RuoYi/Doc/index.vue @@ -0,0 +1,21 @@ + + + diff --git a/zhi-admin-ui/src/components/RuoYi/Git/index.vue b/zhi-admin-ui/src/components/RuoYi/Git/index.vue new file mode 100644 index 0000000..d2d1cd9 --- /dev/null +++ b/zhi-admin-ui/src/components/RuoYi/Git/index.vue @@ -0,0 +1,21 @@ + + + diff --git a/zhi-admin-ui/src/components/Screenfull/index.vue b/zhi-admin-ui/src/components/Screenfull/index.vue new file mode 100644 index 0000000..d4e539c --- /dev/null +++ b/zhi-admin-ui/src/components/Screenfull/index.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/zhi-admin-ui/src/components/SizeSelect/index.vue b/zhi-admin-ui/src/components/SizeSelect/index.vue new file mode 100644 index 0000000..069b5de --- /dev/null +++ b/zhi-admin-ui/src/components/SizeSelect/index.vue @@ -0,0 +1,56 @@ + + + diff --git a/zhi-admin-ui/src/components/SvgIcon/index.vue b/zhi-admin-ui/src/components/SvgIcon/index.vue new file mode 100644 index 0000000..e4bf5ad --- /dev/null +++ b/zhi-admin-ui/src/components/SvgIcon/index.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/zhi-admin-ui/src/components/ThemePicker/index.vue b/zhi-admin-ui/src/components/ThemePicker/index.vue new file mode 100644 index 0000000..1714e1f --- /dev/null +++ b/zhi-admin-ui/src/components/ThemePicker/index.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/zhi-admin-ui/src/components/TopNav/index.vue b/zhi-admin-ui/src/components/TopNav/index.vue new file mode 100644 index 0000000..5f0edbe --- /dev/null +++ b/zhi-admin-ui/src/components/TopNav/index.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/zhi-admin-ui/src/components/WebSocket/WebSocket.vue b/zhi-admin-ui/src/components/WebSocket/WebSocket.vue new file mode 100644 index 0000000..ed09c59 --- /dev/null +++ b/zhi-admin-ui/src/components/WebSocket/WebSocket.vue @@ -0,0 +1,115 @@ + + + + + + diff --git a/zhi-admin-ui/src/components/iFrame/index.vue b/zhi-admin-ui/src/components/iFrame/index.vue new file mode 100644 index 0000000..426857f --- /dev/null +++ b/zhi-admin-ui/src/components/iFrame/index.vue @@ -0,0 +1,36 @@ + + + diff --git a/zhi-admin-ui/src/layout/components/Navbar.vue b/zhi-admin-ui/src/layout/components/Navbar.vue new file mode 100644 index 0000000..99671bc --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Navbar.vue @@ -0,0 +1,200 @@ + + + + + diff --git a/zhi-admin-ui/src/layout/components/Settings/index.vue b/zhi-admin-ui/src/layout/components/Settings/index.vue new file mode 100644 index 0000000..bb3c9ce --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Settings/index.vue @@ -0,0 +1,260 @@ + + + + + diff --git a/zhi-admin-ui/src/layout/components/Sidebar/FixiOSBug.js b/zhi-admin-ui/src/layout/components/Sidebar/FixiOSBug.js new file mode 100644 index 0000000..6823726 --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Sidebar/FixiOSBug.js @@ -0,0 +1,25 @@ +export default { + computed: { + device() { + return this.$store.state.app.device + } + }, + mounted() { + // In order to fix the click on menu on the ios device will trigger the mouseleave bug + this.fixBugIniOS() + }, + methods: { + fixBugIniOS() { + const $subMenu = this.$refs.subMenu + if ($subMenu) { + const handleMouseleave = $subMenu.handleMouseleave + $subMenu.handleMouseleave = (e) => { + if (this.device === 'mobile') { + return + } + handleMouseleave(e) + } + } + } + } +} diff --git a/zhi-admin-ui/src/layout/components/Sidebar/Item.vue b/zhi-admin-ui/src/layout/components/Sidebar/Item.vue new file mode 100644 index 0000000..be3285d --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Sidebar/Item.vue @@ -0,0 +1,33 @@ + diff --git a/zhi-admin-ui/src/layout/components/Sidebar/Link.vue b/zhi-admin-ui/src/layout/components/Sidebar/Link.vue new file mode 100644 index 0000000..8b0bc93 --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Sidebar/Link.vue @@ -0,0 +1,43 @@ + + + diff --git a/zhi-admin-ui/src/layout/components/Sidebar/Logo.vue b/zhi-admin-ui/src/layout/components/Sidebar/Logo.vue new file mode 100644 index 0000000..74464df --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Sidebar/Logo.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/zhi-admin-ui/src/layout/components/Sidebar/SidebarItem.vue b/zhi-admin-ui/src/layout/components/Sidebar/SidebarItem.vue new file mode 100644 index 0000000..4853fbb --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Sidebar/SidebarItem.vue @@ -0,0 +1,100 @@ + + + diff --git a/zhi-admin-ui/src/layout/components/Sidebar/index.vue b/zhi-admin-ui/src/layout/components/Sidebar/index.vue new file mode 100644 index 0000000..51d0839 --- /dev/null +++ b/zhi-admin-ui/src/layout/components/Sidebar/index.vue @@ -0,0 +1,57 @@ + + + diff --git a/zhi-admin-ui/src/layout/components/TagsView/ScrollPane.vue b/zhi-admin-ui/src/layout/components/TagsView/ScrollPane.vue new file mode 100644 index 0000000..bb753a1 --- /dev/null +++ b/zhi-admin-ui/src/layout/components/TagsView/ScrollPane.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/zhi-admin-ui/src/layout/components/TagsView/index.vue b/zhi-admin-ui/src/layout/components/TagsView/index.vue new file mode 100644 index 0000000..cc98071 --- /dev/null +++ b/zhi-admin-ui/src/layout/components/TagsView/index.vue @@ -0,0 +1,332 @@ + + + + + + + diff --git a/zhi-admin-ui/src/layout/components/index.js b/zhi-admin-ui/src/layout/components/index.js new file mode 100644 index 0000000..104bd3a --- /dev/null +++ b/zhi-admin-ui/src/layout/components/index.js @@ -0,0 +1,5 @@ +export { default as AppMain } from './AppMain' +export { default as Navbar } from './Navbar' +export { default as Settings } from './Settings' +export { default as Sidebar } from './Sidebar/index.vue' +export { default as TagsView } from './TagsView/index.vue' diff --git a/zhi-admin-ui/src/layout/index.vue b/zhi-admin-ui/src/layout/index.vue new file mode 100644 index 0000000..f048657 --- /dev/null +++ b/zhi-admin-ui/src/layout/index.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/zhi-admin-ui/src/layout/mixin/ResizeHandler.js b/zhi-admin-ui/src/layout/mixin/ResizeHandler.js new file mode 100644 index 0000000..e8d0df8 --- /dev/null +++ b/zhi-admin-ui/src/layout/mixin/ResizeHandler.js @@ -0,0 +1,45 @@ +import store from '@/store' + +const { body } = document +const WIDTH = 992 // refer to Bootstrap's responsive design + +export default { + watch: { + $route(route) { + if (this.device === 'mobile' && this.sidebar.opened) { + store.dispatch('app/closeSideBar', { withoutAnimation: false }) + } + } + }, + beforeMount() { + window.addEventListener('resize', this.$_resizeHandler) + }, + beforeDestroy() { + window.removeEventListener('resize', this.$_resizeHandler) + }, + mounted() { + const isMobile = this.$_isMobile() + if (isMobile) { + store.dispatch('app/toggleDevice', 'mobile') + store.dispatch('app/closeSideBar', { withoutAnimation: true }) + } + }, + methods: { + // use $_ for mixins properties + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential + $_isMobile() { + const rect = body.getBoundingClientRect() + return rect.width - 1 < WIDTH + }, + $_resizeHandler() { + if (!document.hidden) { + const isMobile = this.$_isMobile() + store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') + + if (isMobile) { + store.dispatch('app/closeSideBar', { withoutAnimation: true }) + } + } + } + } +} diff --git a/zhi-admin-ui/src/main.js b/zhi-admin-ui/src/main.js new file mode 100644 index 0000000..c448ae9 --- /dev/null +++ b/zhi-admin-ui/src/main.js @@ -0,0 +1,110 @@ +import Vue from 'vue' +import Cookies from 'js-cookie' +import Element from 'element-ui' +import './assets/styles/element-variables.scss' +import '@/assets/styles/index.scss' // global css +import '@/assets/styles/ruoyi.scss' // ruoyi css +import App from './App' +import store from './store' +import router from './router' +import directive from './directive' // directive +import plugins from './plugins' // plugins +import { download } from '@/utils/request' + +import './assets/icons' // icon +import './permission' // permission control +import { getDicts } from "@/api/system/dict/data"; +import { getConfigKey, updateConfigByKey } from "@/api/system/config"; +import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi"; +// 分页组件 +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 ImagePreview from "@/components/ImagePreview" +// 字典标签组件 +import DictTag from '@/components/DictTag' +// 头部标签组件 +import VueMeta from 'vue-meta' +// 字典数据组件 +import DictData from '@/components/DictData' +import dayjs from "dayjs"; + +import VueCalendarHeatmap from "vue-calendar-heatmap"; +import VueMarkdownEditor from '@kangc/v-md-editor'; +import '@kangc/v-md-editor/lib/style/base-editor.css'; +import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js'; +import '@kangc/v-md-editor/lib/theme/style/vuepress.css'; +import createEmojiPlugin from '@kangc/v-md-editor/lib/plugins/emoji/index'; +import '@kangc/v-md-editor/lib/plugins/emoji/emoji.css'; +import Prism from 'prismjs'; +// 富文本编辑器 +import mavonEditor from "mavon-editor"; +import "mavon-editor/dist/css/index.css"; + +VueMarkdownEditor.use(vuepressTheme, { + Prism, +}); +VueMarkdownEditor.use(createEmojiPlugin()); + + +// 全局方法挂载 +Vue.prototype.getDicts = getDicts +Vue.prototype.getConfigKey = getConfigKey +Vue.prototype.updateConfigByKey = updateConfigByKey +Vue.prototype.parseTime = parseTime +Vue.prototype.resetForm = resetForm +Vue.prototype.addDateRange = addDateRange +Vue.prototype.selectDictLabel = selectDictLabel +Vue.prototype.selectDictLabels = selectDictLabels +Vue.prototype.download = download +Vue.prototype.handleTree = handleTree +Vue.prototype.$moment = dayjs; + +// 全局组件挂载 +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.component('ImagePreview', ImagePreview) + +Vue.use(directive) +Vue.use(plugins) +Vue.use(VueMeta) +Vue.use(VueMarkdownEditor); +Vue.use(VueCalendarHeatmap); +Vue.use(mavonEditor); +DictData.install() + +/** + * If you don't want to use mock-server + * you want to use MockJs for mock api + * you can execute: mockXHR() + * + * Currently MockJs will be used in the production environment, + * please remove it before going online! ! ! + */ + +// 修改 el-dialog 默认点击遮照为不关闭 +Element.Dialog.props.closeOnClickModal.default = false + +Vue.use(Element, { + size: Cookies.get('size') || 'medium' // set element-ui default size +}) + +Vue.config.productionTip = false + +new Vue({ + el: '#app', + router, + store, + render: h => h(App) +}) diff --git a/zhi-admin-ui/src/permission.js b/zhi-admin-ui/src/permission.js new file mode 100644 index 0000000..4da3e7f --- /dev/null +++ b/zhi-admin-ui/src/permission.js @@ -0,0 +1,56 @@ +import router from './router' +import store from './store' +import { Message } from 'element-ui' +import NProgress from 'nprogress' +import 'nprogress/nprogress.css' +import { getToken } from '@/utils/auth' +import { isRelogin } from '@/utils/request' + +NProgress.configure({ showSpinner: false }) + +const whiteList = ['/login', '/auth-redirect', '/bind', '/register','/article/articles/*'] + +router.beforeEach((to, from, next) => { + NProgress.start() + if (getToken()) { + to.meta.title && store.dispatch('settings/setTitle', to.meta.title) + /* has token*/ + if (to.path === '/login') { + next({ path: '/' }) + NProgress.done() + } else { + if (store.getters.roles.length === 0) { + isRelogin.show = true + // 判断当前用户是否已拉取完user_info信息 + store.dispatch('GetInfo').then(() => { + isRelogin.show = false + store.dispatch('GenerateRoutes').then(accessRoutes => { + // 根据roles权限生成可访问的路由表 + router.addRoutes(accessRoutes) // 动态添加可访问路由表 + next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 + }) + }).catch(err => { + store.dispatch('LogOut').then(() => { + Message.error(err) + next({ path: '/' }) + }) + }) + } else { + next() + } + } + } else { + // 没有token + if (whiteList.indexOf(to.path) !== -1) { + // 在免登录白名单,直接进入 + next() + } else { + next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 + NProgress.done() + } + } +}) + +router.afterEach(() => { + NProgress.done() +}) diff --git a/zhi-admin-ui/src/plugins/auth.js b/zhi-admin-ui/src/plugins/auth.js new file mode 100644 index 0000000..6c6bc24 --- /dev/null +++ b/zhi-admin-ui/src/plugins/auth.js @@ -0,0 +1,60 @@ +import store from '@/store' + +function authPermission(permission) { + const all_permission = "*:*:*"; + const permissions = store.getters && store.getters.permissions + if (permission && permission.length > 0) { + return permissions.some(v => { + return all_permission === v || v === permission + }) + } else { + return false + } +} + +function authRole(role) { + const super_admin = "admin"; + const roles = store.getters && store.getters.roles + if (role && role.length > 0) { + return roles.some(v => { + return super_admin === v || v === role + }) + } else { + return false + } +} + +export default { + // 验证用户是否具备某权限 + hasPermi(permission) { + return authPermission(permission); + }, + // 验证用户是否含有指定权限,只需包含其中一个 + hasPermiOr(permissions) { + return permissions.some(item => { + return authPermission(item) + }) + }, + // 验证用户是否含有指定权限,必须全部拥有 + hasPermiAnd(permissions) { + return permissions.every(item => { + return authPermission(item) + }) + }, + // 验证用户是否具备某角色 + hasRole(role) { + return authRole(role); + }, + // 验证用户是否含有指定角色,只需包含其中一个 + hasRoleOr(roles) { + return roles.some(item => { + return authRole(item) + }) + }, + // 验证用户是否含有指定角色,必须全部拥有 + hasRoleAnd(roles) { + return roles.every(item => { + return authRole(item) + }) + } +} diff --git a/zhi-admin-ui/src/plugins/cache.js b/zhi-admin-ui/src/plugins/cache.js new file mode 100644 index 0000000..6b5c00b --- /dev/null +++ b/zhi-admin-ui/src/plugins/cache.js @@ -0,0 +1,77 @@ +const sessionCache = { + set (key, value) { + if (!sessionStorage) { + return + } + if (key != null && value != null) { + sessionStorage.setItem(key, value) + } + }, + get (key) { + if (!sessionStorage) { + return null + } + if (key == null) { + return null + } + return sessionStorage.getItem(key) + }, + setJSON (key, jsonValue) { + if (jsonValue != null) { + this.set(key, JSON.stringify(jsonValue)) + } + }, + getJSON (key) { + const value = this.get(key) + if (value != null) { + return JSON.parse(value) + } + }, + remove (key) { + sessionStorage.removeItem(key); + } +} +const localCache = { + set (key, value) { + if (!localStorage) { + return + } + if (key != null && value != null) { + localStorage.setItem(key, value) + } + }, + get (key) { + if (!localStorage) { + return null + } + if (key == null) { + return null + } + return localStorage.getItem(key) + }, + setJSON (key, jsonValue) { + if (jsonValue != null) { + this.set(key, JSON.stringify(jsonValue)) + } + }, + getJSON (key) { + const value = this.get(key) + if (value != null) { + return JSON.parse(value) + } + }, + remove (key) { + localStorage.removeItem(key); + } +} + +export default { + /** + * 会话级缓存 + */ + session: sessionCache, + /** + * 本地缓存 + */ + local: localCache +} diff --git a/zhi-admin-ui/src/plugins/download.js b/zhi-admin-ui/src/plugins/download.js new file mode 100644 index 0000000..85138bb --- /dev/null +++ b/zhi-admin-ui/src/plugins/download.js @@ -0,0 +1,65 @@ +import axios from 'axios' +import {Loading, Message} from 'element-ui' +import { saveAs } from 'file-saver' +import { getToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { blobValidate } from "@/utils/ruoyi"; + +const baseURL = process.env.VUE_APP_BASE_API +let downloadLoadingInstance; + +export default { + oss(ossId) { + var url = baseURL + '/system/oss/download/' + ossId + downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) + axios({ + method: 'get', + url: url, + responseType: 'blob', + headers: { 'Authorization': 'Bearer ' + getToken() } + }).then(async (res) => { + const isLogin = await blobValidate(res.data); + if (isLogin) { + const blob = new Blob([res.data], { type: 'application/octet-stream' }) + this.saveAs(blob, decodeURI(res.headers['download-filename'])) + } else { + this.printErrMsg(res.data); + } + downloadLoadingInstance.close(); + }).catch((r) => { + console.error(r) + Message.error('下载文件出现错误,请联系管理员!') + downloadLoadingInstance.close(); + }) + }, + zip(url, name) { + var url = baseURL + url + axios({ + method: 'get', + url: url, + responseType: 'blob', + headers: { + 'Authorization': 'Bearer ' + getToken(), + 'datasource': localStorage.getItem("dataName") + } + }).then(async (res) => { + const isLogin = await blobValidate(res.data); + if (isLogin) { + const blob = new Blob([res.data], { type: 'application/zip' }) + this.saveAs(blob, name) + } else { + this.printErrMsg(res.data); + } + }) + }, + saveAs(text, name, opts) { + saveAs(text, name, opts); + }, + async printErrMsg(data) { + const resText = await data.text(); + const rspObj = JSON.parse(resText); + const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] + Message.error(errMsg); + } +} + diff --git a/zhi-admin-ui/src/plugins/index.js b/zhi-admin-ui/src/plugins/index.js new file mode 100644 index 0000000..d000f2d --- /dev/null +++ b/zhi-admin-ui/src/plugins/index.js @@ -0,0 +1,20 @@ +import tab from './tab' +import auth from './auth' +import cache from './cache' +import modal from './modal' +import download from './download' + +export default { + install(Vue) { + // 页签操作 + Vue.prototype.$tab = tab + // 认证对象 + Vue.prototype.$auth = auth + // 缓存对象 + Vue.prototype.$cache = cache + // 模态框对象 + Vue.prototype.$modal = modal + // 下载文件 + Vue.prototype.$download = download + } +} diff --git a/zhi-admin-ui/src/plugins/modal.js b/zhi-admin-ui/src/plugins/modal.js new file mode 100644 index 0000000..b37ca14 --- /dev/null +++ b/zhi-admin-ui/src/plugins/modal.js @@ -0,0 +1,83 @@ +import { Message, MessageBox, Notification, Loading } from 'element-ui' + +let loadingInstance; + +export default { + // 消息提示 + msg(content) { + Message.info(content) + }, + // 错误消息 + msgError(content) { + Message.error(content) + }, + // 成功消息 + msgSuccess(content) { + Message.success(content) + }, + // 警告消息 + msgWarning(content) { + Message.warning(content) + }, + // 弹出提示 + alert(content) { + MessageBox.alert(content, "系统提示") + }, + // 错误提示 + alertError(content) { + MessageBox.alert(content, "系统提示", { type: 'error' }) + }, + // 成功提示 + alertSuccess(content) { + MessageBox.alert(content, "系统提示", { type: 'success' }) + }, + // 警告提示 + alertWarning(content) { + MessageBox.alert(content, "系统提示", { type: 'warning' }) + }, + // 通知提示 + notify(content) { + Notification.info(content) + }, + // 错误通知 + notifyError(content) { + Notification.error(content); + }, + // 成功通知 + notifySuccess(content) { + Notification.success(content) + }, + // 警告通知 + notifyWarning(content) { + Notification.warning(content) + }, + // 确认窗体 + confirm(content) { + return MessageBox.confirm(content, "系统提示", { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: "warning", + }) + }, + // 提交内容 + prompt(content) { + return MessageBox.prompt(content, "系统提示", { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: "warning", + }) + }, + // 打开遮罩层 + loading(content) { + loadingInstance = Loading.service({ + lock: true, + text: content, + spinner: "el-icon-loading", + background: "rgba(0, 0, 0, 0.7)", + }) + }, + // 关闭遮罩层 + closeLoading() { + loadingInstance.close(); + } +} diff --git a/zhi-admin-ui/src/plugins/tab.js b/zhi-admin-ui/src/plugins/tab.js new file mode 100644 index 0000000..cade9f7 --- /dev/null +++ b/zhi-admin-ui/src/plugins/tab.js @@ -0,0 +1,67 @@ +import store from '@/store' +import router from '@/router'; + +export default { + // 刷新当前tab页签 + refreshPage(obj) { + const { path, query, matched } = router.currentRoute; + if (obj === undefined) { + matched.forEach((m) => { + if (m.components && m.components.default && m.components.default.name) { + if (!['Layout', 'ParentView'].includes(m.components.default.name)) { + obj = { name: m.components.default.name, path: path, query: query }; + } + } + }); + } + return store.dispatch('tagsView/delCachedView', obj).then(() => { + const { path, query } = obj + router.replace({ + path: '/redirect' + path, + query: query + }) + }) + }, + // 关闭当前tab页签,打开新页签 + closeOpenPage(obj) { + store.dispatch("tagsView/delView", router.currentRoute); + if (obj !== undefined) { + return router.push(obj); + } + }, + // 关闭指定tab页签 + closePage(obj) { + if (obj === undefined) { + return store.dispatch('tagsView/delView', router.currentRoute).then(({ lastPath }) => { + return router.push(lastPath || '/'); + }); + } + return store.dispatch('tagsView/delView', obj); + }, + // 关闭所有tab页签 + closeAllPage() { + return store.dispatch('tagsView/delAllViews'); + }, + // 关闭左侧tab页签 + closeLeftPage(obj) { + return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute); + }, + // 关闭右侧tab页签 + closeRightPage(obj) { + return store.dispatch('tagsView/delRightTags', obj || router.currentRoute); + }, + // 关闭其他tab页签 + closeOtherPage(obj) { + return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute); + }, + // 添加tab页签 + openPage(title, url, params) { + var obj = { path: url, meta: { title: title } } + store.dispatch('tagsView/addView', obj); + return router.push({ path: url, query: params }); + }, + // 修改tab页签 + updatePage(obj) { + return store.dispatch('tagsView/updateVisitedView', obj); + } +} diff --git a/zhi-admin-ui/src/router/index.js b/zhi-admin-ui/src/router/index.js new file mode 100644 index 0000000..dd4d5f1 --- /dev/null +++ b/zhi-admin-ui/src/router/index.js @@ -0,0 +1,178 @@ +import Vue from 'vue' +import Router from 'vue-router' + +Vue.use(Router) + +/* Layout */ +import Layout from '@/layout' + +/** + * Note: 路由配置项 + * + * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 + * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 + * // 若你想不管路由下面的 children 声明的个数都显示你的根路由 + * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 + * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + * name:'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题 + * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 + * roles: ['admin', 'common'] // 访问路由的角色权限 + * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 + * meta : { + noCache: true // 如果设置为true,则不会被 缓存(默认 false) + title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 + icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg + breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示 + activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。 + } + */ + +// 公共路由 +export const constantRoutes = [ + { + path: '/redirect', + component: Layout, + hidden: true, + children: [ + { + path: '/redirect/:path(.*)', + component: () => import('@/views/redirect') + } + ] + }, + { + path: '/login', + component: () => import('@/views/login'), + hidden: true + }, + { + path: '/register', + component: () => import('@/views/register'), + hidden: true + }, + { + path: '/404', + component: () => import('@/views/error/404'), + hidden: true + }, + { + path: '/401', + component: () => import('@/views/error/401'), + hidden: true + }, + { + path: '', + component: Layout, + redirect: 'index', + children: [ + { + path: 'index', + component: () => import('@/views/index'), + name: 'Index', + meta: { title: '首页', icon: 'dashboard', affix: true } + } + ] + }, + { + path: '/user', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'profile', + component: () => import('@/views/system/user/profile/index'), + name: 'Profile', + meta: { title: '个人中心', icon: 'user' } + } + ] + } +] + +// 动态路由,基于用户权限动态去加载 +export const dynamicRoutes = [ + { + path: '/system/user-auth', + component: Layout, + hidden: true, + permissions: ['system:user:edit'], + children: [ + { + path: 'role/:userId(\\d+)', + component: () => import('@/views/system/user/authRole'), + name: 'AuthRole', + meta: { title: '分配角色', activeMenu: '/system/user' } + } + ] + }, + { + path: '/system/role-auth', + component: Layout, + hidden: true, + permissions: ['system:role:edit'], + children: [ + { + path: 'user/:roleId(\\d+)', + component: () => import('@/views/system/role/authUser'), + name: 'AuthUser', + meta: { title: '分配用户', activeMenu: '/system/role' } + } + ] + }, + { + path: '/system/dict-data', + component: Layout, + hidden: true, + permissions: ['system:dict:list'], + children: [ + { + path: 'index/:dictId(\\d+)', + component: () => import('@/views/system/dict/data'), + name: 'Data', + meta: { title: '字典数据', activeMenu: '/system/dict' } + } + ] + }, + { + path: '/system/oss-config', + component: Layout, + hidden: true, + permissions: ['system:oss:list'], + children: [ + { + path: 'index', + component: () => import('@/views/system/oss/config'), + name: 'OssConfig', + meta: { title: '配置管理', activeMenu: '/system/oss' } + } + ] + }, + { + path: '/tool/gen-edit', + component: Layout, + hidden: true, + permissions: ['tool:gen:edit'], + children: [ + { + path: 'index/:tableId(\\d+)', + component: () => import('@/views/tool/gen/editTable'), + name: 'GenEdit', + meta: { title: '修改生成配置', activeMenu: '/tool/gen' } + } + ] + } +] + +// 防止连续点击多次路由报错 +let routerPush = Router.prototype.push; +Router.prototype.push = function push(location) { + return routerPush.call(this, location).catch(err => err) +} + +export default new Router({ + base: process.env.VUE_APP_CONTEXT_PATH, + mode: 'history', // 去掉url中的# + scrollBehavior: () => ({ y: 0 }), + routes: constantRoutes +}) diff --git a/zhi-admin-ui/src/settings.js b/zhi-admin-ui/src/settings.js new file mode 100644 index 0000000..6a0b09f --- /dev/null +++ b/zhi-admin-ui/src/settings.js @@ -0,0 +1,44 @@ +module.exports = { + /** + * 侧边栏主题 深色主题theme-dark,浅色主题theme-light + */ + sideTheme: 'theme-dark', + + /** + * 是否系统布局配置 + */ + showSettings: false, + + /** + * 是否显示顶部导航 + */ + topNav: false, + + /** + * 是否显示 tagsView + */ + tagsView: true, + + /** + * 是否固定头部 + */ + fixedHeader: false, + + /** + * 是否显示logo + */ + sidebarLogo: true, + + /** + * 是否显示动态标题 + */ + dynamicTitle: false, + + /** + * @type {string | array} 'production' | ['production', 'development'] + * @description Need show err logs component. + * The default is only used in the production env + * If you want to also use it in dev, you can pass ['production', 'development'] + */ + errorLog: 'production' +} diff --git a/zhi-admin-ui/src/store/getters.js b/zhi-admin-ui/src/store/getters.js new file mode 100644 index 0000000..8adb1b6 --- /dev/null +++ b/zhi-admin-ui/src/store/getters.js @@ -0,0 +1,19 @@ +const getters = { + sidebar: state => state.app.sidebar, + size: state => state.app.size, + device: state => state.app.device, + dict: state => state.dict.dict, + visitedViews: state => state.tagsView.visitedViews, + cachedViews: state => state.tagsView.cachedViews, + token: state => state.user.token, + avatar: state => state.user.avatar, + name: state => state.user.name, + introduction: state => state.user.introduction, + roles: state => state.user.roles, + permissions: state => state.user.permissions, + permission_routes: state => state.permission.routes, + topbarRouters:state => state.permission.topbarRouters, + defaultRoutes:state => state.permission.defaultRoutes, + sidebarRouters:state => state.permission.sidebarRouters, +} +export default getters diff --git a/zhi-admin-ui/src/store/index.js b/zhi-admin-ui/src/store/index.js new file mode 100644 index 0000000..97aaef8 --- /dev/null +++ b/zhi-admin-ui/src/store/index.js @@ -0,0 +1,25 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import app from './modules/app' +import dict from './modules/dict' +import user from './modules/user' +import tagsView from './modules/tagsView' +import permission from './modules/permission' +import settings from './modules/settings' +import getters from './getters' + +Vue.use(Vuex) + +const store = new Vuex.Store({ + modules: { + app, + dict, + user, + tagsView, + permission, + settings + }, + getters +}) + +export default store diff --git a/zhi-admin-ui/src/store/modules/app.js b/zhi-admin-ui/src/store/modules/app.js new file mode 100644 index 0000000..3e22d1c --- /dev/null +++ b/zhi-admin-ui/src/store/modules/app.js @@ -0,0 +1,66 @@ +import Cookies from 'js-cookie' + +const state = { + sidebar: { + opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, + withoutAnimation: false, + hide: false + }, + device: 'desktop', + size: Cookies.get('size') || 'medium' +} + +const mutations = { + TOGGLE_SIDEBAR: state => { + if (state.sidebar.hide) { + return false; + } + state.sidebar.opened = !state.sidebar.opened + state.sidebar.withoutAnimation = false + if (state.sidebar.opened) { + Cookies.set('sidebarStatus', 1) + } else { + Cookies.set('sidebarStatus', 0) + } + }, + CLOSE_SIDEBAR: (state, withoutAnimation) => { + Cookies.set('sidebarStatus', 0) + state.sidebar.opened = false + state.sidebar.withoutAnimation = withoutAnimation + }, + TOGGLE_DEVICE: (state, device) => { + state.device = device + }, + SET_SIZE: (state, size) => { + state.size = size + Cookies.set('size', size) + }, + SET_SIDEBAR_HIDE: (state, status) => { + state.sidebar.hide = status + } +} + +const actions = { + toggleSideBar({ commit }) { + commit('TOGGLE_SIDEBAR') + }, + closeSideBar({ commit }, { withoutAnimation }) { + commit('CLOSE_SIDEBAR', withoutAnimation) + }, + toggleDevice({ commit }, device) { + commit('TOGGLE_DEVICE', device) + }, + setSize({ commit }, size) { + commit('SET_SIZE', size) + }, + toggleSideBarHide({ commit }, status) { + commit('SET_SIDEBAR_HIDE', status) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/zhi-admin-ui/src/store/modules/dict.js b/zhi-admin-ui/src/store/modules/dict.js new file mode 100644 index 0000000..f95bead --- /dev/null +++ b/zhi-admin-ui/src/store/modules/dict.js @@ -0,0 +1,50 @@ +const state = { + dict: new Array() +} +const mutations = { + SET_DICT: (state, { key, value }) => { + if (key !== null && key !== "") { + state.dict.push({ + key: key, + value: value + }) + } + }, + REMOVE_DICT: (state, key) => { + try { + for (let i = 0; i < state.dict.length; i++) { + if (state.dict[i].key == key) { + state.dict.splice(i, i) + return true + } + } + } catch (e) { + } + }, + CLEAN_DICT: (state) => { + state.dict = new Array() + } +} + +const actions = { + // 设置字典 + setDict({ commit }, data) { + commit('SET_DICT', data) + }, + // 删除字典 + removeDict({ commit }, key) { + commit('REMOVE_DICT', key) + }, + // 清空字典 + cleanDict({ commit }) { + commit('CLEAN_DICT') + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} + diff --git a/zhi-admin-ui/src/store/modules/permission.js b/zhi-admin-ui/src/store/modules/permission.js new file mode 100644 index 0000000..2287665 --- /dev/null +++ b/zhi-admin-ui/src/store/modules/permission.js @@ -0,0 +1,133 @@ +import auth from '@/plugins/auth' +import router, { constantRoutes, dynamicRoutes } from '@/router' +import { getRouters } from '@/api/menu' +import Layout from '@/layout/index' +import ParentView from '@/components/ParentView' +import InnerLink from '@/layout/components/InnerLink' + +const permission = { + state: { + routes: [], + addRoutes: [], + defaultRoutes: [], + topbarRouters: [], + sidebarRouters: [] + }, + mutations: { + SET_ROUTES: (state, routes) => { + state.addRoutes = routes + state.routes = constantRoutes.concat(routes) + }, + SET_DEFAULT_ROUTES: (state, routes) => { + state.defaultRoutes = constantRoutes.concat(routes) + }, + SET_TOPBAR_ROUTES: (state, routes) => { + state.topbarRouters = routes + }, + SET_SIDEBAR_ROUTERS: (state, routes) => { + state.sidebarRouters = routes + }, + }, + actions: { + // 生成路由 + GenerateRoutes({ commit }) { + return new Promise(resolve => { + // 向后端请求路由数据 + getRouters().then(res => { + const sdata = JSON.parse(JSON.stringify(res.data)) + const rdata = JSON.parse(JSON.stringify(res.data)) + const sidebarRoutes = filterAsyncRouter(sdata) + const rewriteRoutes = filterAsyncRouter(rdata, false, true) + const asyncRoutes = filterDynamicRoutes(dynamicRoutes); + rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true }) + router.addRoutes(asyncRoutes); + commit('SET_ROUTES', rewriteRoutes) + commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes)) + commit('SET_DEFAULT_ROUTES', sidebarRoutes) + commit('SET_TOPBAR_ROUTES', sidebarRoutes) + resolve(rewriteRoutes) + }) + }) + } + } +} + +// 遍历后台传来的路由字符串,转换为组件对象 +function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) { + return asyncRouterMap.filter(route => { + if (type && route.children) { + route.children = filterChildren(route.children) + } + if (route.component) { + // Layout ParentView 组件特殊处理 + if (route.component === 'Layout') { + 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) + } + } + if (route.children != null && route.children && route.children.length) { + route.children = filterAsyncRouter(route.children, route, type) + } else { + delete route['children'] + delete route['redirect'] + } + return true + }) +} + +function filterChildren(childrenMap, lastRouter = false) { + var children = [] + childrenMap.forEach((el, index) => { + if (el.children && el.children.length) { + if (el.component === 'ParentView' && !lastRouter) { + el.children.forEach(c => { + c.path = el.path + '/' + c.path + if (c.children && c.children.length) { + children = children.concat(filterChildren(c.children, c)) + return + } + children.push(c) + }) + return + } + } + if (lastRouter) { + el.path = lastRouter.path + '/' + el.path + } + children = children.concat(el) + }) + return children +} + +// 动态路由遍历,验证是否具备权限 +export function filterDynamicRoutes(routes) { + const res = [] + routes.forEach(route => { + if (route.permissions) { + if (auth.hasPermiOr(route.permissions)) { + res.push(route) + } + } else if (route.roles) { + if (auth.hasRoleOr(route.roles)) { + res.push(route) + } + } + }) + return res +} + +export const loadView = (view) => { + if (process.env.NODE_ENV === 'development') { + return (resolve) => require([`@/views/${view}`], resolve) + } else { + // 使用 import 实现生产环境的路由懒加载 + return () => import(`@/views/${view}`) + } +} + +export default permission diff --git a/zhi-admin-ui/src/store/modules/settings.js b/zhi-admin-ui/src/store/modules/settings.js new file mode 100644 index 0000000..2455a1e --- /dev/null +++ b/zhi-admin-ui/src/store/modules/settings.js @@ -0,0 +1,42 @@ +import defaultSettings from '@/settings' + +const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings + +const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || '' +const state = { + title: '', + theme: storageSetting.theme || '#409EFF', + sideTheme: storageSetting.sideTheme || sideTheme, + showSettings: showSettings, + topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav, + tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView, + fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader, + sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo, + dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle +} +const mutations = { + CHANGE_SETTING: (state, { key, value }) => { + if (state.hasOwnProperty(key)) { + state[key] = value + } + } +} + +const actions = { + // 修改布局设置 + changeSetting({ commit }, data) { + commit('CHANGE_SETTING', data) + }, + // 设置网页标题 + setTitle({ commit }, title) { + state.title = title + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} + diff --git a/zhi-admin-ui/src/store/modules/tagsView.js b/zhi-admin-ui/src/store/modules/tagsView.js new file mode 100644 index 0000000..5fc011c --- /dev/null +++ b/zhi-admin-ui/src/store/modules/tagsView.js @@ -0,0 +1,228 @@ +const state = { + visitedViews: [], + cachedViews: [], + iframeViews: [] +} + +const mutations = { + ADD_IFRAME_VIEW: (state, view) => { + if (state.iframeViews.some(v => v.path === view.path)) return + state.iframeViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + }, + ADD_VISITED_VIEW: (state, view) => { + if (state.visitedViews.some(v => v.path === view.path)) return + state.visitedViews.push( + Object.assign({}, view, { + title: view.meta.title || 'no-name' + }) + ) + }, + ADD_CACHED_VIEW: (state, view) => { + if (state.cachedViews.includes(view.name)) return + if (view.meta && !view.meta.noCache) { + state.cachedViews.push(view.name) + } + }, + DEL_VISITED_VIEW: (state, view) => { + for (const [i, v] of state.visitedViews.entries()) { + if (v.path === view.path) { + state.visitedViews.splice(i, 1) + break + } + } + state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) + }, + DEL_IFRAME_VIEW: (state, view) => { + state.iframeViews = state.iframeViews.filter(item => item.path !== view.path) + }, + DEL_CACHED_VIEW: (state, view) => { + const index = state.cachedViews.indexOf(view.name) + index > -1 && state.cachedViews.splice(index, 1) + }, + + DEL_OTHERS_VISITED_VIEWS: (state, view) => { + state.visitedViews = state.visitedViews.filter(v => { + return v.meta.affix || v.path === view.path + }) + state.iframeViews = state.iframeViews.filter(item => item.path === view.path) + }, + DEL_OTHERS_CACHED_VIEWS: (state, view) => { + const index = state.cachedViews.indexOf(view.name) + if (index > -1) { + state.cachedViews = state.cachedViews.slice(index, index + 1) + } else { + state.cachedViews = [] + } + }, + DEL_ALL_VISITED_VIEWS: state => { + // keep affix tags + const affixTags = state.visitedViews.filter(tag => tag.meta.affix) + state.visitedViews = affixTags + state.iframeViews = [] + }, + DEL_ALL_CACHED_VIEWS: state => { + state.cachedViews = [] + }, + UPDATE_VISITED_VIEW: (state, view) => { + for (let v of state.visitedViews) { + if (v.path === view.path) { + v = Object.assign(v, view) + break + } + } + }, + DEL_RIGHT_VIEWS: (state, view) => { + const index = state.visitedViews.findIndex(v => v.path === view.path) + if (index === -1) { + return + } + state.visitedViews = state.visitedViews.filter((item, idx) => { + if (idx <= index || (item.meta && item.meta.affix)) { + return true + } + const i = state.cachedViews.indexOf(item.name) + if (i > -1) { + state.cachedViews.splice(i, 1) + } + if(item.meta.link) { + const fi = state.iframeViews.findIndex(v => v.path === item.path) + state.iframeViews.splice(fi, 1) + } + return false + }) + }, + DEL_LEFT_VIEWS: (state, view) => { + const index = state.visitedViews.findIndex(v => v.path === view.path) + if (index === -1) { + return + } + state.visitedViews = state.visitedViews.filter((item, idx) => { + if (idx >= index || (item.meta && item.meta.affix)) { + return true + } + const i = state.cachedViews.indexOf(item.name) + if (i > -1) { + state.cachedViews.splice(i, 1) + } + if(item.meta.link) { + const fi = state.iframeViews.findIndex(v => v.path === item.path) + state.iframeViews.splice(fi, 1) + } + return false + }) + } +} + +const actions = { + addView({ dispatch }, view) { + dispatch('addVisitedView', view) + dispatch('addCachedView', view) + }, + addIframeView({ commit }, view) { + commit('ADD_IFRAME_VIEW', view) + }, + addVisitedView({ commit }, view) { + commit('ADD_VISITED_VIEW', view) + }, + addCachedView({ commit }, view) { + commit('ADD_CACHED_VIEW', view) + }, + delView({ dispatch, state }, view) { + return new Promise(resolve => { + dispatch('delVisitedView', view) + dispatch('delCachedView', view) + resolve({ + visitedViews: [...state.visitedViews], + cachedViews: [...state.cachedViews] + }) + }) + }, + delVisitedView({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_VISITED_VIEW', view) + resolve([...state.visitedViews]) + }) + }, + delIframeView({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_IFRAME_VIEW', view) + resolve([...state.iframeViews]) + }) + }, + delCachedView({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_CACHED_VIEW', view) + resolve([...state.cachedViews]) + }) + }, + delOthersViews({ dispatch, state }, view) { + return new Promise(resolve => { + dispatch('delOthersVisitedViews', view) + dispatch('delOthersCachedViews', view) + resolve({ + visitedViews: [...state.visitedViews], + cachedViews: [...state.cachedViews] + }) + }) + }, + delOthersVisitedViews({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_OTHERS_VISITED_VIEWS', view) + resolve([...state.visitedViews]) + }) + }, + delOthersCachedViews({ commit, state }, view) { + return new Promise(resolve => { + commit('DEL_OTHERS_CACHED_VIEWS', view) + resolve([...state.cachedViews]) + }) + }, + delAllViews({ dispatch, state }, view) { + return new Promise(resolve => { + dispatch('delAllVisitedViews', view) + dispatch('delAllCachedViews', view) + resolve({ + visitedViews: [...state.visitedViews], + cachedViews: [...state.cachedViews] + }) + }) + }, + delAllVisitedViews({ commit, state }) { + return new Promise(resolve => { + commit('DEL_ALL_VISITED_VIEWS') + resolve([...state.visitedViews]) + }) + }, + delAllCachedViews({ commit, state }) { + return new Promise(resolve => { + commit('DEL_ALL_CACHED_VIEWS') + resolve([...state.cachedViews]) + }) + }, + updateVisitedView({ commit }, view) { + commit('UPDATE_VISITED_VIEW', view) + }, + delRightTags({ commit }, view) { + return new Promise(resolve => { + commit('DEL_RIGHT_VIEWS', view) + resolve([...state.visitedViews]) + }) + }, + delLeftTags({ commit }, view) { + return new Promise(resolve => { + commit('DEL_LEFT_VIEWS', view) + resolve([...state.visitedViews]) + }) + }, +} + +export default { + namespaced: true, + state, + mutations, + actions +} diff --git a/zhi-admin-ui/src/store/modules/user.js b/zhi-admin-ui/src/store/modules/user.js new file mode 100644 index 0000000..d67c9a4 --- /dev/null +++ b/zhi-admin-ui/src/store/modules/user.js @@ -0,0 +1,96 @@ +import { login, logout, getInfo } from '@/api/login' +import { getToken, setToken, removeToken } from '@/utils/auth' + +const user = { + state: { + token: getToken(), + name: '', + avatar: '', + roles: [], + permissions: [] + }, + + mutations: { + SET_TOKEN: (state, token) => { + state.token = token + }, + SET_NAME: (state, name) => { + state.name = name + }, + SET_AVATAR: (state, avatar) => { + state.avatar = avatar + }, + SET_ROLES: (state, roles) => { + state.roles = roles + }, + SET_PERMISSIONS: (state, permissions) => { + state.permissions = permissions + } + }, + + actions: { + // 登录 + Login({ commit }, userInfo) { + const username = userInfo.username.trim() + const password = userInfo.password + const code = userInfo.code + const uuid = userInfo.uuid + return new Promise((resolve, reject) => { + login(username, password, code, uuid).then(res => { + setToken(res.data.token) + commit('SET_TOKEN', res.data.token) + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 获取用户信息 + GetInfo({ commit, state }) { + return new Promise((resolve, reject) => { + getInfo().then(res => { + const user = res.data.user + const avatar = (user.avatar == "" || user.avatar == null) ? require("@/assets/images/profile.jpg") : user.avatar; + if (res.data.roles && res.data.roles.length > 0) { // 验证返回的roles是否是一个非空数组 + commit('SET_ROLES', res.data.roles) + commit('SET_PERMISSIONS', res.data.permissions) + } else { + commit('SET_ROLES', ['ROLE_DEFAULT']) + } + commit('SET_NAME', user.userName) + commit('SET_AVATAR', avatar) + resolve(res) + }).catch(error => { + reject(error) + }) + }) + }, + + // 退出系统 + LogOut({ commit, state }) { + return new Promise((resolve, reject) => { + logout(state.token).then(() => { + commit('SET_TOKEN', '') + commit('SET_ROLES', []) + commit('SET_PERMISSIONS', []) + removeToken() + resolve() + }).catch(error => { + reject(error) + }) + }) + }, + + // 前端 登出 + FedLogOut({ commit }) { + return new Promise(resolve => { + commit('SET_TOKEN', '') + removeToken() + resolve() + }) + } + } +} + +export default user diff --git a/zhi-admin-ui/src/utils/auth.js b/zhi-admin-ui/src/utils/auth.js new file mode 100644 index 0000000..08a43d6 --- /dev/null +++ b/zhi-admin-ui/src/utils/auth.js @@ -0,0 +1,15 @@ +import Cookies from 'js-cookie' + +const TokenKey = 'Admin-Token' + +export function getToken() { + return Cookies.get(TokenKey) +} + +export function setToken(token) { + return Cookies.set(TokenKey, token) +} + +export function removeToken() { + return Cookies.remove(TokenKey) +} diff --git a/zhi-admin-ui/src/utils/dict/Dict.js b/zhi-admin-ui/src/utils/dict/Dict.js new file mode 100644 index 0000000..104bd6e --- /dev/null +++ b/zhi-admin-ui/src/utils/dict/Dict.js @@ -0,0 +1,82 @@ +import Vue from 'vue' +import { mergeRecursive } from "@/utils/ruoyi"; +import DictMeta from './DictMeta' +import DictData from './DictData' + +const DEFAULT_DICT_OPTIONS = { + types: [], +} + +/** + * @classdesc 字典 + * @property {Object} label 标签对象,内部属性名为字典类型名称 + * @property {Object} dict 字段数组,内部属性名为字典类型名称 + * @property {Array.} _dictMetas 字典元数据数组 + */ +export default class Dict { + constructor() { + this.owner = null + this.label = {} + this.type = {} + } + + init(options) { + if (options instanceof Array) { + options = { types: options } + } + const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options) + if (opts.types === undefined) { + throw new Error('need dict types') + } + const ps = [] + this._dictMetas = opts.types.map(t => DictMeta.parse(t)) + this._dictMetas.forEach(dictMeta => { + const type = dictMeta.type + Vue.set(this.label, type, {}) + Vue.set(this.type, type, []) + if (dictMeta.lazy) { + return + } + ps.push(loadDict(this, dictMeta)) + }) + return Promise.all(ps) + } + + /** + * 重新加载字典 + * @param {String} type 字典类型 + */ + reloadDict(type) { + const dictMeta = this._dictMetas.find(e => e.type === type) + if (dictMeta === undefined) { + return Promise.reject(`the dict meta of ${type} was not found`) + } + return loadDict(this, dictMeta) + } +} + +/** + * 加载字典 + * @param {Dict} dict 字典 + * @param {DictMeta} dictMeta 字典元数据 + * @returns {Promise} + */ +function loadDict(dict, dictMeta) { + return dictMeta.request(dictMeta) + .then(response => { + const type = dictMeta.type + let dicts = dictMeta.responseConverter(response, dictMeta) + if (!(dicts instanceof Array)) { + console.error('the return of responseConverter must be Array.') + dicts = [] + } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) { + console.error('the type of elements in dicts must be DictData') + dicts = [] + } + dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts) + dicts.forEach(d => { + Vue.set(dict.label[type], d.value, d.label) + }) + return dicts + }) +} diff --git a/zhi-admin-ui/src/utils/dict/DictConverter.js b/zhi-admin-ui/src/utils/dict/DictConverter.js new file mode 100644 index 0000000..0cf5df8 --- /dev/null +++ b/zhi-admin-ui/src/utils/dict/DictConverter.js @@ -0,0 +1,17 @@ +import DictOptions from './DictOptions' +import DictData from './DictData' + +export default function(dict, dictMeta) { + const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS) + const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS) + return new DictData(dict[label], dict[value], dict) +} + +/** + * 确定字典字段 + * @param {DictData} dict + * @param {...String} fields + */ +function determineDictField(dict, ...fields) { + return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f)) +} diff --git a/zhi-admin-ui/src/utils/dict/DictData.js b/zhi-admin-ui/src/utils/dict/DictData.js new file mode 100644 index 0000000..afc763e --- /dev/null +++ b/zhi-admin-ui/src/utils/dict/DictData.js @@ -0,0 +1,13 @@ +/** + * @classdesc 字典数据 + * @property {String} label 标签 + * @property {*} value 标签 + * @property {Object} raw 原始数据 + */ +export default class DictData { + constructor(label, value, raw) { + this.label = label + this.value = value + this.raw = raw + } +} diff --git a/zhi-admin-ui/src/utils/dict/DictMeta.js b/zhi-admin-ui/src/utils/dict/DictMeta.js new file mode 100644 index 0000000..9779daa --- /dev/null +++ b/zhi-admin-ui/src/utils/dict/DictMeta.js @@ -0,0 +1,38 @@ +import { mergeRecursive } from "@/utils/ruoyi"; +import DictOptions from './DictOptions' + +/** + * @classdesc 字典元数据 + * @property {String} type 类型 + * @property {Function} request 请求 + * @property {String} label 标签字段 + * @property {String} value 值字段 + */ +export default class DictMeta { + constructor(options) { + this.type = options.type + this.request = options.request + this.responseConverter = options.responseConverter + this.labelField = options.labelField + this.valueField = options.valueField + this.lazy = options.lazy === true + } +} + + +/** + * 解析字典元数据 + * @param {Object} options + * @returns {DictMeta} + */ +DictMeta.parse= function(options) { + let opts = null + if (typeof options === 'string') { + opts = DictOptions.metas[options] || {} + opts.type = options + } else if (typeof options === 'object') { + opts = options + } + opts = mergeRecursive(DictOptions.metas['*'], opts) + return new DictMeta(opts) +} diff --git a/zhi-admin-ui/src/utils/dict/DictOptions.js b/zhi-admin-ui/src/utils/dict/DictOptions.js new file mode 100644 index 0000000..338a94e --- /dev/null +++ b/zhi-admin-ui/src/utils/dict/DictOptions.js @@ -0,0 +1,51 @@ +import { mergeRecursive } from "@/utils/ruoyi"; +import dictConverter from './DictConverter' + +export const options = { + metas: { + '*': { + /** + * 字典请求,方法签名为function(dictMeta: DictMeta): Promise + */ + request: (dictMeta) => { + console.log(`load dict ${dictMeta.type}`) + return Promise.resolve([]) + }, + /** + * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData + */ + responseConverter, + labelField: 'label', + valueField: 'value', + }, + }, + /** + * 默认标签字段 + */ + DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'], + /** + * 默认值字段 + */ + DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'], +} + +/** + * 映射字典 + * @param {Object} response 字典数据 + * @param {DictMeta} dictMeta 字典元数据 + * @returns {DictData} + */ +function responseConverter(response, dictMeta) { + const dicts = response.content instanceof Array ? response.content : response + if (dicts === undefined) { + console.warn(`no dict data of "${dictMeta.type}" found in the response`) + return [] + } + return dicts.map(d => dictConverter(d, dictMeta)) +} + +export function mergeOptions(src) { + mergeRecursive(options, src) +} + +export default options diff --git a/zhi-admin-ui/src/utils/dict/index.js b/zhi-admin-ui/src/utils/dict/index.js new file mode 100644 index 0000000..215eb9e --- /dev/null +++ b/zhi-admin-ui/src/utils/dict/index.js @@ -0,0 +1,33 @@ +import Dict from './Dict' +import { mergeOptions } from './DictOptions' + +export default function(Vue, options) { + mergeOptions(options) + Vue.mixin({ + data() { + if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) { + return {} + } + const dict = new Dict() + dict.owner = this + return { + dict + } + }, + created() { + if (!(this.dict instanceof Dict)) { + return + } + options.onCreated && options.onCreated(this.dict) + this.dict.init(this.$options.dicts).then(() => { + options.onReady && options.onReady(this.dict) + this.$nextTick(() => { + this.$emit('dictReady', this.dict) + if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) { + this.$options.methods.onDictReady.call(this, this.dict) + } + }) + }) + }, + }) +} diff --git a/zhi-admin-ui/src/utils/errorCode.js b/zhi-admin-ui/src/utils/errorCode.js new file mode 100644 index 0000000..d2111ee --- /dev/null +++ b/zhi-admin-ui/src/utils/errorCode.js @@ -0,0 +1,6 @@ +export default { + '401': '认证失败,无法访问系统资源', + '403': '当前操作没有权限', + '404': '访问资源不存在', + 'default': '系统未知错误,请反馈给管理员' +} diff --git a/zhi-admin-ui/src/utils/generator/config.js b/zhi-admin-ui/src/utils/generator/config.js new file mode 100644 index 0000000..7abf227 --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/config.js @@ -0,0 +1,438 @@ +export const formConf = { + formRef: 'elForm', + formModel: 'formData', + size: 'medium', + labelPosition: 'right', + labelWidth: 100, + formRules: 'rules', + gutter: 15, + disabled: false, + span: 24, + formBtns: true +} + +export const inputComponents = [ + { + label: '单行文本', + tag: 'el-input', + tagIcon: 'input', + placeholder: '请输入', + defaultValue: undefined, + span: 24, + labelWidth: null, + style: { width: '100%' }, + clearable: true, + prepend: '', + append: '', + 'prefix-icon': '', + 'suffix-icon': '', + maxlength: null, + 'show-word-limit': false, + readonly: false, + disabled: false, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/input' + }, + { + label: '多行文本', + tag: 'el-input', + tagIcon: 'textarea', + type: 'textarea', + placeholder: '请输入', + defaultValue: undefined, + span: 24, + labelWidth: null, + autosize: { + minRows: 4, + maxRows: 4 + }, + style: { width: '100%' }, + maxlength: null, + 'show-word-limit': false, + readonly: false, + disabled: false, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/input' + }, + { + label: '密码', + tag: 'el-input', + tagIcon: 'password', + placeholder: '请输入', + defaultValue: undefined, + span: 24, + 'show-password': true, + labelWidth: null, + style: { width: '100%' }, + clearable: true, + prepend: '', + append: '', + 'prefix-icon': '', + 'suffix-icon': '', + maxlength: null, + 'show-word-limit': false, + readonly: false, + disabled: false, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/input' + }, + { + label: '计数器', + tag: 'el-input-number', + tagIcon: 'number', + placeholder: '', + defaultValue: undefined, + span: 24, + labelWidth: null, + min: undefined, + max: undefined, + step: undefined, + 'step-strictly': false, + precision: undefined, + 'controls-position': '', + disabled: false, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/input-number' + } +] + +export const selectComponents = [ + { + label: '下拉选择', + tag: 'el-select', + tagIcon: 'select', + placeholder: '请选择', + defaultValue: undefined, + span: 24, + labelWidth: null, + style: { width: '100%' }, + clearable: true, + disabled: false, + required: true, + filterable: false, + multiple: false, + options: [{ + label: '选项一', + value: 1 + }, { + label: '选项二', + value: 2 + }], + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/select' + }, + { + label: '级联选择', + tag: 'el-cascader', + tagIcon: 'cascader', + placeholder: '请选择', + defaultValue: [], + span: 24, + labelWidth: null, + style: { width: '100%' }, + props: { + props: { + multiple: false + } + }, + 'show-all-levels': true, + disabled: false, + clearable: true, + filterable: false, + required: true, + options: [{ + id: 1, + value: 1, + label: '选项1', + children: [{ + id: 2, + value: 2, + label: '选项1-1' + }] + }], + dataType: 'dynamic', + labelKey: 'label', + valueKey: 'value', + childrenKey: 'children', + separator: '/', + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/cascader' + }, + { + label: '单选框组', + tag: 'el-radio-group', + tagIcon: 'radio', + defaultValue: undefined, + span: 24, + labelWidth: null, + style: {}, + optionType: 'default', + border: false, + size: 'medium', + disabled: false, + required: true, + options: [{ + label: '选项一', + value: 1 + }, { + label: '选项二', + value: 2 + }], + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/radio' + }, + { + label: '多选框组', + tag: 'el-checkbox-group', + tagIcon: 'checkbox', + defaultValue: [], + span: 24, + labelWidth: null, + style: {}, + optionType: 'default', + border: false, + size: 'medium', + disabled: false, + required: true, + options: [{ + label: '选项一', + value: 1 + }, { + label: '选项二', + value: 2 + }], + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/checkbox' + }, + { + label: '开关', + tag: 'el-switch', + tagIcon: 'switch', + defaultValue: false, + span: 24, + labelWidth: null, + style: {}, + disabled: false, + required: true, + 'active-text': '', + 'inactive-text': '', + 'active-color': null, + 'inactive-color': null, + 'active-value': true, + 'inactive-value': false, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/switch' + }, + { + label: '滑块', + tag: 'el-slider', + tagIcon: 'slider', + defaultValue: null, + span: 24, + labelWidth: null, + disabled: false, + required: true, + min: 0, + max: 100, + step: 1, + 'show-stops': false, + range: false, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/slider' + }, + { + label: '时间选择', + tag: 'el-time-picker', + tagIcon: 'time', + placeholder: '请选择', + defaultValue: null, + span: 24, + labelWidth: null, + style: { width: '100%' }, + disabled: false, + clearable: true, + required: true, + 'picker-options': { + selectableRange: '00:00:00-23:59:59' + }, + format: 'HH:mm:ss', + 'value-format': 'HH:mm:ss', + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/time-picker' + }, + { + label: '时间范围', + tag: 'el-time-picker', + tagIcon: 'time-range', + defaultValue: null, + span: 24, + labelWidth: null, + style: { width: '100%' }, + disabled: false, + clearable: true, + required: true, + 'is-range': true, + 'range-separator': '至', + 'start-placeholder': '开始时间', + 'end-placeholder': '结束时间', + format: 'HH:mm:ss', + 'value-format': 'HH:mm:ss', + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/time-picker' + }, + { + label: '日期选择', + tag: 'el-date-picker', + tagIcon: 'date', + placeholder: '请选择', + defaultValue: null, + type: 'date', + span: 24, + labelWidth: null, + style: { width: '100%' }, + disabled: false, + clearable: true, + required: true, + format: 'yyyy-MM-dd', + 'value-format': 'yyyy-MM-dd', + readonly: false, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/date-picker' + }, + { + label: '日期范围', + tag: 'el-date-picker', + tagIcon: 'date-range', + defaultValue: null, + span: 24, + labelWidth: null, + style: { width: '100%' }, + type: 'daterange', + 'range-separator': '至', + 'start-placeholder': '开始日期', + 'end-placeholder': '结束日期', + disabled: false, + clearable: true, + required: true, + format: 'yyyy-MM-dd', + 'value-format': 'yyyy-MM-dd', + readonly: false, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/date-picker' + }, + { + label: '评分', + tag: 'el-rate', + tagIcon: 'rate', + defaultValue: 0, + span: 24, + labelWidth: null, + style: {}, + max: 5, + 'allow-half': false, + 'show-text': false, + 'show-score': false, + disabled: false, + required: true, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/rate' + }, + { + label: '颜色选择', + tag: 'el-color-picker', + tagIcon: 'color', + defaultValue: null, + labelWidth: null, + 'show-alpha': false, + 'color-format': '', + disabled: false, + required: true, + size: 'medium', + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/color-picker' + }, + { + label: '上传', + tag: 'el-upload', + tagIcon: 'upload', + action: 'https://jsonplaceholder.typicode.com/posts/', + defaultValue: null, + labelWidth: null, + disabled: false, + required: true, + accept: '', + name: 'file', + 'auto-upload': true, + showTip: false, + buttonText: '点击上传', + fileSize: 2, + sizeUnit: 'MB', + 'list-type': 'text', + multiple: false, + regList: [], + changeTag: true, + document: 'https://element.eleme.cn/#/zh-CN/component/upload' + } +] + +export const layoutComponents = [ + { + layout: 'rowFormItem', + tagIcon: 'row', + type: 'default', + justify: 'start', + align: 'top', + label: '行容器', + layoutTree: true, + children: [], + document: 'https://element.eleme.cn/#/zh-CN/component/layout' + }, + { + layout: 'colFormItem', + label: '按钮', + changeTag: true, + labelWidth: null, + tag: 'el-button', + tagIcon: 'button', + span: 24, + default: '主要按钮', + type: 'primary', + icon: 'el-icon-search', + size: 'medium', + disabled: false, + document: 'https://element.eleme.cn/#/zh-CN/component/button' + } +] + +// 组件rule的触发方式,无触发方式的组件不生成rule +export const trigger = { + 'el-input': 'blur', + 'el-input-number': 'blur', + 'el-select': 'change', + 'el-radio-group': 'change', + 'el-checkbox-group': 'change', + 'el-cascader': 'change', + 'el-time-picker': 'change', + 'el-date-picker': 'change', + 'el-rate': 'change' +} diff --git a/zhi-admin-ui/src/utils/generator/css.js b/zhi-admin-ui/src/utils/generator/css.js new file mode 100644 index 0000000..c1c62e6 --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/css.js @@ -0,0 +1,18 @@ +const styles = { + 'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}', + 'el-upload': '.el-upload__tip{line-height: 1.2;}' +} + +function addCss(cssList, el) { + const css = styles[el.tag] + css && cssList.indexOf(css) === -1 && cssList.push(css) + if (el.children) { + el.children.forEach(el2 => addCss(cssList, el2)) + } +} + +export function makeUpCss(conf) { + const cssList = [] + conf.fields.forEach(el => addCss(cssList, el)) + return cssList.join('\n') +} diff --git a/zhi-admin-ui/src/utils/generator/drawingDefault.js b/zhi-admin-ui/src/utils/generator/drawingDefault.js new file mode 100644 index 0000000..09f133c --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/drawingDefault.js @@ -0,0 +1,29 @@ +export default [ + { + layout: 'colFormItem', + tagIcon: 'input', + label: '手机号', + vModel: 'mobile', + formId: 6, + tag: 'el-input', + placeholder: '请输入手机号', + defaultValue: '', + span: 24, + style: { width: '100%' }, + clearable: true, + prepend: '', + append: '', + 'prefix-icon': 'el-icon-mobile', + 'suffix-icon': '', + maxlength: 11, + 'show-word-limit': true, + readonly: false, + disabled: false, + required: true, + changeTag: true, + regList: [{ + pattern: '/^1(3|4|5|7|8|9)\\d{9}$/', + message: '手机号格式错误' + }] + } +] diff --git a/zhi-admin-ui/src/utils/generator/html.js b/zhi-admin-ui/src/utils/generator/html.js new file mode 100644 index 0000000..9bcc536 --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/html.js @@ -0,0 +1,359 @@ +/* eslint-disable max-len */ +import { trigger } from './config' + +let confGlobal +let someSpanIsNot24 + +export function dialogWrapper(str) { + return ` + ${str} +
+ 取消 + 确定 +
+
` +} + +export function vueTemplate(str) { + return `` +} + +export function vueScript(str) { + return `` +} + +export function cssStyle(cssStr) { + return `` +} + +function buildFormTemplate(conf, child, type) { + let labelPosition = '' + if (conf.labelPosition !== 'right') { + labelPosition = `label-position="${conf.labelPosition}"` + } + const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : '' + let str = ` + ${child} + ${buildFromBtns(conf, type)} + ` + if (someSpanIsNot24) { + str = ` + ${str} + ` + } + return str +} + +function buildFromBtns(conf, type) { + let str = '' + if (conf.formBtns && type === 'file') { + str = ` + 提交 + 重置 + ` + if (someSpanIsNot24) { + str = ` + ${str} + ` + } + } + return str +} + +// span不为24的用el-col包裹 +function colWrapper(element, str) { + if (someSpanIsNot24 || element.span !== 24) { + return ` + ${str} + ` + } + return str +} + +const layouts = { + colFormItem(element) { + let labelWidth = '' + if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) { + labelWidth = `label-width="${element.labelWidth}px"` + } + const required = !trigger[element.tag] && element.required ? 'required' : '' + const tagDom = tags[element.tag] ? tags[element.tag](element) : null + let str = ` + ${tagDom} + ` + str = colWrapper(element, str) + return str + }, + rowFormItem(element) { + const type = element.type === 'default' ? '' : `type="${element.type}"` + const justify = element.type === 'default' ? '' : `justify="${element.justify}"` + const align = element.type === 'default' ? '' : `align="${element.align}"` + const gutter = element.gutter ? `gutter="${element.gutter}"` : '' + const children = element.children.map(el => layouts[el.layout](el)) + let str = ` + ${children.join('\n')} + ` + str = colWrapper(element, str) + return str + } +} + +const tags = { + 'el-button': el => { + const { + tag, disabled + } = attrBuilder(el) + const type = el.type ? `type="${el.type}"` : '' + const icon = el.icon ? `icon="${el.icon}"` : '' + const size = el.size ? `size="${el.size}"` : '' + let child = buildElButtonChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}` + }, + 'el-input': el => { + const { + disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : '' + const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : '' + const readonly = el.readonly ? 'readonly' : '' + const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : '' + const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : '' + const showPassword = el['show-password'] ? 'show-password' : '' + const type = el.type ? `type="${el.type}"` : '' + const autosize = el.autosize && el.autosize.minRows + ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"` + : '' + let child = buildElInputChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}` + }, + 'el-input-number': el => { + const { disabled, vModel, placeholder } = attrBuilder(el) + const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : '' + const min = el.min ? `:min='${el.min}'` : '' + const max = el.max ? `:max='${el.max}'` : '' + const step = el.step ? `:step='${el.step}'` : '' + const stepStrictly = el['step-strictly'] ? 'step-strictly' : '' + const precision = el.precision ? `:precision='${el.precision}'` : '' + + return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}>` + }, + 'el-select': el => { + const { + disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const filterable = el.filterable ? 'filterable' : '' + const multiple = el.multiple ? 'multiple' : '' + let child = buildElSelectChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}` + }, + 'el-radio-group': el => { + const { disabled, vModel } = attrBuilder(el) + const size = `size="${el.size}"` + let child = buildElRadioGroupChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${el.tag} ${vModel} ${size} ${disabled}>${child}` + }, + 'el-checkbox-group': el => { + const { disabled, vModel } = attrBuilder(el) + const size = `size="${el.size}"` + const min = el.min ? `:min="${el.min}"` : '' + const max = el.max ? `:max="${el.max}"` : '' + let child = buildElCheckboxGroupChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}` + }, + 'el-switch': el => { + const { disabled, vModel } = attrBuilder(el) + const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : '' + const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : '' + const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : '' + const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : '' + const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : '' + const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : '' + + return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}>` + }, + 'el-cascader': el => { + const { + disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const options = el.options ? `:options="${el.vModel}Options"` : '' + const props = el.props ? `:props="${el.vModel}Props"` : '' + const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"' + const filterable = el.filterable ? 'filterable' : '' + const separator = el.separator === '/' ? '' : `separator="${el.separator}"` + + return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}>` + }, + 'el-slider': el => { + const { disabled, vModel } = attrBuilder(el) + const min = el.min ? `:min='${el.min}'` : '' + const max = el.max ? `:max='${el.max}'` : '' + const step = el.step ? `:step='${el.step}'` : '' + const range = el.range ? 'range' : '' + const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : '' + + return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}>` + }, + 'el-time-picker': el => { + const { + disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : '' + const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : '' + const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : '' + const isRange = el['is-range'] ? 'is-range' : '' + const format = el.format ? `format="${el.format}"` : '' + const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : '' + const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : '' + + return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}>` + }, + 'el-date-picker': el => { + const { + disabled, vModel, clearable, placeholder, width + } = attrBuilder(el) + const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : '' + const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : '' + const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : '' + const format = el.format ? `format="${el.format}"` : '' + const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : '' + const type = el.type === 'date' ? '' : `type="${el.type}"` + const readonly = el.readonly ? 'readonly' : '' + + return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}>` + }, + 'el-rate': el => { + const { disabled, vModel } = attrBuilder(el) + const max = el.max ? `:max='${el.max}'` : '' + const allowHalf = el['allow-half'] ? 'allow-half' : '' + const showText = el['show-text'] ? 'show-text' : '' + const showScore = el['show-score'] ? 'show-score' : '' + + return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}>` + }, + 'el-color-picker': el => { + const { disabled, vModel } = attrBuilder(el) + const size = `size="${el.size}"` + const showAlpha = el['show-alpha'] ? 'show-alpha' : '' + const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : '' + + return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}>` + }, + 'el-upload': el => { + const disabled = el.disabled ? ':disabled=\'true\'' : '' + const action = el.action ? `:action="${el.vModel}Action"` : '' + const multiple = el.multiple ? 'multiple' : '' + const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : '' + const accept = el.accept ? `accept="${el.accept}"` : '' + const name = el.name !== 'file' ? `name="${el.name}"` : '' + const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : '' + const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"` + const fileList = `:file-list="${el.vModel}fileList"` + const ref = `ref="${el.vModel}"` + let child = buildElUploadChild(el) + + if (child) child = `\n${child}\n` // 换行 + return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}` + } +} + +function attrBuilder(el) { + return { + vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`, + clearable: el.clearable ? 'clearable' : '', + placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '', + width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '', + disabled: el.disabled ? ':disabled=\'true\'' : '' + } +} + +// el-buttin 子级 +function buildElButtonChild(conf) { + const children = [] + if (conf.default) { + children.push(conf.default) + } + return children.join('\n') +} + +// el-input innerHTML +function buildElInputChild(conf) { + const children = [] + if (conf.prepend) { + children.push(``) + } + if (conf.append) { + children.push(``) + } + return children.join('\n') +} + +function buildElSelectChild(conf) { + const children = [] + if (conf.options && conf.options.length) { + children.push(``) + } + return children.join('\n') +} + +function buildElRadioGroupChild(conf) { + const children = [] + if (conf.options && conf.options.length) { + const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio' + const border = conf.border ? 'border' : '' + children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) + } + return children.join('\n') +} + +function buildElCheckboxGroupChild(conf) { + const children = [] + if (conf.options && conf.options.length) { + const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox' + const border = conf.border ? 'border' : '' + children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}`) + } + return children.join('\n') +} + +function buildElUploadChild(conf) { + const list = [] + if (conf['list-type'] === 'picture-card') list.push('') + else list.push(`${conf.buttonText}`) + if (conf.showTip) list.push(`
只能上传不超过 ${conf.fileSize}${conf.sizeUnit} 的${conf.accept}文件
`) + return list.join('\n') +} + +export function makeUpHtml(conf, type) { + const htmlList = [] + confGlobal = conf + someSpanIsNot24 = conf.fields.some(item => item.span !== 24) + conf.fields.forEach(el => { + htmlList.push(layouts[el.layout](el)) + }) + const htmlStr = htmlList.join('\n') + + let temp = buildFormTemplate(conf, htmlStr, type) + if (type === 'dialog') { + temp = dialogWrapper(temp) + } + confGlobal = null + return temp +} diff --git a/zhi-admin-ui/src/utils/generator/icon.json b/zhi-admin-ui/src/utils/generator/icon.json new file mode 100644 index 0000000..2d9999a --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/icon.json @@ -0,0 +1 @@ +["platform-eleme","eleme","delete-solid","delete","s-tools","setting","user-solid","user","phone","phone-outline","more","more-outline","star-on","star-off","s-goods","goods","warning","warning-outline","question","info","remove","circle-plus","success","error","zoom-in","zoom-out","remove-outline","circle-plus-outline","circle-check","circle-close","s-help","help","minus","plus","check","close","picture","picture-outline","picture-outline-round","upload","upload2","download","camera-solid","camera","video-camera-solid","video-camera","message-solid","bell","s-cooperation","s-order","s-platform","s-fold","s-unfold","s-operation","s-promotion","s-home","s-release","s-ticket","s-management","s-open","s-shop","s-marketing","s-flag","s-comment","s-finance","s-claim","s-custom","s-opportunity","s-data","s-check","s-grid","menu","share","d-caret","caret-left","caret-right","caret-bottom","caret-top","bottom-left","bottom-right","back","right","bottom","top","top-left","top-right","arrow-left","arrow-right","arrow-down","arrow-up","d-arrow-left","d-arrow-right","video-pause","video-play","refresh","refresh-right","refresh-left","finished","sort","sort-up","sort-down","rank","loading","view","c-scale-to-original","date","edit","edit-outline","folder","folder-opened","folder-add","folder-remove","folder-delete","folder-checked","tickets","document-remove","document-delete","document-copy","document-checked","document","document-add","printer","paperclip","takeaway-box","search","monitor","attract","mobile","scissors","umbrella","headset","brush","mouse","coordinate","magic-stick","reading","data-line","data-board","pie-chart","data-analysis","collection-tag","film","suitcase","suitcase-1","receiving","collection","files","notebook-1","notebook-2","toilet-paper","office-building","school","table-lamp","house","no-smoking","smoking","shopping-cart-full","shopping-cart-1","shopping-cart-2","shopping-bag-1","shopping-bag-2","sold-out","sell","present","box","bank-card","money","coin","wallet","discount","price-tag","news","guide","male","female","thumb","cpu","link","connection","open","turn-off","set-up","chat-round","chat-line-round","chat-square","chat-dot-round","chat-dot-square","chat-line-square","message","postcard","position","turn-off-microphone","microphone","close-notification","bangzhu","time","odometer","crop","aim","switch-button","full-screen","copy-document","mic","stopwatch","medal-1","medal","trophy","trophy-1","first-aid-kit","discover","place","location","location-outline","location-information","add-location","delete-location","map-location","alarm-clock","timer","watch-1","watch","lock","unlock","key","service","mobile-phone","bicycle","truck","ship","basketball","football","soccer","baseball","wind-power","light-rain","lightning","heavy-rain","sunrise","sunrise-1","sunset","sunny","cloudy","partly-cloudy","cloudy-and-sunny","moon","moon-night","dish","dish-1","food","chicken","fork-spoon","knife-fork","burger","tableware","sugar","dessert","ice-cream","hot-water","water-cup","coffee-cup","cold-drink","goblet","goblet-full","goblet-square","goblet-square-full","refrigerator","grape","watermelon","cherry","apple","pear","orange","coffee","ice-tea","ice-drink","milk-tea","potato-strips","lollipop","ice-cream-square","ice-cream-round"] \ No newline at end of file diff --git a/zhi-admin-ui/src/utils/generator/js.js b/zhi-admin-ui/src/utils/generator/js.js new file mode 100644 index 0000000..35e3e21 --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/js.js @@ -0,0 +1,236 @@ +import { isArray } from 'util' +import { exportDefault, titleCase } from '@/utils/index' +import { trigger } from './config' + +const units = { + KB: '1024', + MB: '1024 / 1024', + GB: '1024 / 1024 / 1024' +} +let confGlobal +const inheritAttrs = { + file: '', + dialog: 'inheritAttrs: false,' +} + + +export function makeUpJs(conf, type) { + confGlobal = conf = JSON.parse(JSON.stringify(conf)) + const dataList = [] + const ruleList = [] + const optionsList = [] + const propsList = [] + const methodList = mixinMethod(type) + const uploadVarList = [] + + conf.fields.forEach(el => { + buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) + }) + + const script = buildexport( + conf, + type, + dataList.join('\n'), + ruleList.join('\n'), + optionsList.join('\n'), + uploadVarList.join('\n'), + propsList.join('\n'), + methodList.join('\n') + ) + confGlobal = null + return script +} + +function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) { + buildData(el, dataList) + buildRules(el, ruleList) + + if (el.options && el.options.length) { + buildOptions(el, optionsList) + if (el.dataType === 'dynamic') { + const model = `${el.vModel}Options` + const options = titleCase(model) + buildOptionMethod(`get${options}`, model, methodList) + } + } + + if (el.props && el.props.props) { + buildProps(el, propsList) + } + + if (el.action && el.tag === 'el-upload') { + uploadVarList.push( + `${el.vModel}Action: '${el.action}', + ${el.vModel}fileList: [],` + ) + methodList.push(buildBeforeUpload(el)) + if (!el['auto-upload']) { + methodList.push(buildSubmitUpload(el)) + } + } + + if (el.children) { + el.children.forEach(el2 => { + buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) + }) + } +} + +function mixinMethod(type) { + const list = []; const + minxins = { + file: confGlobal.formBtns ? { + submitForm: `submitForm() { + this.$refs['${confGlobal.formRef}'].validate(valid => { + if(!valid) return + // TODO 提交表单 + }) + },`, + resetForm: `resetForm() { + this.$refs['${confGlobal.formRef}'].resetFields() + },` + } : null, + dialog: { + onOpen: 'onOpen() {},', + onClose: `onClose() { + this.$refs['${confGlobal.formRef}'].resetFields() + },`, + close: `close() { + this.$emit('update:visible', false) + },`, + handleConfirm: `handleConfirm() { + this.$refs['${confGlobal.formRef}'].validate(valid => { + if(!valid) return + this.close() + }) + },` + } + } + + const methods = minxins[type] + if (methods) { + Object.keys(methods).forEach(key => { + list.push(methods[key]) + }) + } + + return list +} + +function buildData(conf, dataList) { + if (conf.vModel === undefined) return + let defaultValue + if (typeof (conf.defaultValue) === 'string' && !conf.multiple) { + defaultValue = `'${conf.defaultValue}'` + } else { + defaultValue = `${JSON.stringify(conf.defaultValue)}` + } + dataList.push(`${conf.vModel}: ${defaultValue},`) +} + +function buildRules(conf, ruleList) { + if (conf.vModel === undefined) return + const rules = [] + if (trigger[conf.tag]) { + if (conf.required) { + const type = isArray(conf.defaultValue) ? 'type: \'array\',' : '' + let message = isArray(conf.defaultValue) ? `请至少选择一个${conf.vModel}` : conf.placeholder + if (message === undefined) message = `${conf.label}不能为空` + rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`) + } + if (conf.regList && isArray(conf.regList)) { + conf.regList.forEach(item => { + if (item.pattern) { + rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`) + } + }) + } + ruleList.push(`${conf.vModel}: [${rules.join(',')}],`) + } +} + +function buildOptions(conf, optionsList) { + if (conf.vModel === undefined) return + if (conf.dataType === 'dynamic') { conf.options = [] } + const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},` + optionsList.push(str) +} + +function buildProps(conf, propsList) { + if (conf.dataType === 'dynamic') { + conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey) + conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey) + conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey) + } + const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},` + propsList.push(str) +} + +function buildBeforeUpload(conf) { + const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const + returnList = [] + if (conf.fileSize) { + rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize} + if(!isRightSize){ + this.$message.error('文件大小超过 ${conf.fileSize}${conf.sizeUnit}') + }` + returnList.push('isRightSize') + } + if (conf.accept) { + acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type) + if(!isAccept){ + this.$message.error('应该选择${conf.accept}类型的文件') + }` + returnList.push('isAccept') + } + const str = `${conf.vModel}BeforeUpload(file) { + ${rightSizeCode} + ${acceptCode} + return ${returnList.join('&&')} + },` + return returnList.length ? str : '' +} + +function buildSubmitUpload(conf) { + const str = `submitUpload() { + this.$refs['${conf.vModel}'].submit() + },` + return str +} + +function buildOptionMethod(methodName, model, methodList) { + const str = `${methodName}() { + // TODO 发起请求获取数据 + this.${model} + },` + methodList.push(str) +} + +function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) { + const str = `${exportDefault}{ + ${inheritAttrs[type]} + components: {}, + props: [], + data () { + return { + ${conf.formModel}: { + ${data} + }, + ${conf.formRules}: { + ${rules} + }, + ${uploadVar} + ${selectOptions} + ${props} + } + }, + computed: {}, + watch: {}, + created () {}, + mounted () {}, + methods: { + ${methods} + } +}` + return str +} diff --git a/zhi-admin-ui/src/utils/generator/render.js b/zhi-admin-ui/src/utils/generator/render.js new file mode 100644 index 0000000..e8640f0 --- /dev/null +++ b/zhi-admin-ui/src/utils/generator/render.js @@ -0,0 +1,126 @@ +import { makeMap } from '@/utils/index' + +// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js +const isAttr = makeMap( + 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' + + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' + + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,' + + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,' + + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,' + + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' + + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' + + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' + + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' + + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' + + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' + + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' + + 'target,title,type,usemap,value,width,wrap' +) + +function vModel(self, dataObject, defaultValue) { + dataObject.props.value = defaultValue + + dataObject.on.input = val => { + self.$emit('input', val) + } +} + +const componentChild = { + 'el-button': { + default(h, conf, key) { + return conf[key] + }, + }, + 'el-input': { + prepend(h, conf, key) { + return + }, + append(h, conf, key) { + return + } + }, + 'el-select': { + options(h, conf, key) { + const list = [] + conf.options.forEach(item => { + list.push() + }) + return list + } + }, + 'el-radio-group': { + options(h, conf, key) { + const list = [] + conf.options.forEach(item => { + if (conf.optionType === 'button') list.push({item.label}) + else list.push({item.label}) + }) + return list + } + }, + 'el-checkbox-group': { + options(h, conf, key) { + const list = [] + conf.options.forEach(item => { + if (conf.optionType === 'button') { + list.push({item.label}) + } else { + list.push({item.label}) + } + }) + return list + } + }, + 'el-upload': { + 'list-type': (h, conf, key) => { + const list = [] + if (conf['list-type'] === 'picture-card') { + list.push() + } else { + list.push({conf.buttonText}) + } + if (conf.showTip) { + list.push(
只能上传不超过 {conf.fileSize}{conf.sizeUnit} 的{conf.accept}文件
) + } + return list + } + } +} + +export default { + render(h) { + const dataObject = { + attrs: {}, + props: {}, + on: {}, + style: {} + } + const confClone = JSON.parse(JSON.stringify(this.conf)) + const children = [] + + const childObjs = componentChild[confClone.tag] + if (childObjs) { + Object.keys(childObjs).forEach(key => { + const childFunc = childObjs[key] + if (confClone[key]) { + children.push(childFunc(h, confClone, key)) + } + }) + } + + Object.keys(confClone).forEach(key => { + const val = confClone[key] + if (key === 'vModel') { + vModel(this, dataObject, confClone.defaultValue) + } else if (dataObject[key]) { + dataObject[key] = val + } else if (!isAttr(key)) { + dataObject.props[key] = val + } else { + dataObject.attrs[key] = val + } + }) + return h(this.conf.tag, dataObject, children) + }, + props: ['conf'] +} diff --git a/zhi-admin-ui/src/utils/index.js b/zhi-admin-ui/src/utils/index.js new file mode 100644 index 0000000..df5db12 --- /dev/null +++ b/zhi-admin-ui/src/utils/index.js @@ -0,0 +1,390 @@ +import { parseTime } from './ruoyi' + +/** + * 表格时间格式化 + */ +export function formatDate(cellValue) { + if (cellValue == null || cellValue == "") return ""; + var date = new Date(cellValue) + var year = date.getFullYear() + var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1 + var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() + var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() + var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() + var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds() + return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds +} + +/** + * @param {number} time + * @param {string} option + * @returns {string} + */ +export function formatTime(time, option) { + if (('' + time).length === 10) { + time = parseInt(time) * 1000 + } else { + time = +time + } + const d = new Date(time) + const now = Date.now() + + const diff = (now - d) / 1000 + + if (diff < 30) { + return '刚刚' + } else if (diff < 3600) { + // less 1 hour + return Math.ceil(diff / 60) + '分钟前' + } else if (diff < 3600 * 24) { + return Math.ceil(diff / 3600) + '小时前' + } else if (diff < 3600 * 24 * 2) { + return '1天前' + } + if (option) { + return parseTime(time, option) + } else { + return ( + d.getMonth() + + 1 + + '月' + + d.getDate() + + '日' + + d.getHours() + + '时' + + d.getMinutes() + + '分' + ) + } +} + +/** + * @param {string} url + * @returns {Object} + */ +export function getQueryObject(url) { + url = url == null ? window.location.href : url + const search = url.substring(url.lastIndexOf('?') + 1) + const obj = {} + const reg = /([^?&=]+)=([^?&=]*)/g + search.replace(reg, (rs, $1, $2) => { + const name = decodeURIComponent($1) + let val = decodeURIComponent($2) + val = String(val) + obj[name] = val + return rs + }) + return obj +} + +/** + * @param {string} input value + * @returns {number} output value + */ +export function byteLength(str) { + // returns the byte length of an utf8 string + let s = str.length + for (var i = str.length - 1; i >= 0; i--) { + const code = str.charCodeAt(i) + if (code > 0x7f && code <= 0x7ff) s++ + else if (code > 0x7ff && code <= 0xffff) s += 2 + if (code >= 0xDC00 && code <= 0xDFFF) i-- + } + return s +} + +/** + * @param {Array} actual + * @returns {Array} + */ +export function cleanArray(actual) { + const newArray = [] + for (let i = 0; i < actual.length; i++) { + if (actual[i]) { + newArray.push(actual[i]) + } + } + return newArray +} + +/** + * @param {Object} json + * @returns {Array} + */ +export function param(json) { + if (!json) return '' + return cleanArray( + Object.keys(json).map(key => { + if (json[key] === undefined) return '' + return encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) + }) + ).join('&') +} + +/** + * @param {string} url + * @returns {Object} + */ +export function param2Obj(url) { + const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') + if (!search) { + return {} + } + const obj = {} + const searchArr = search.split('&') + searchArr.forEach(v => { + const index = v.indexOf('=') + if (index !== -1) { + const name = v.substring(0, index) + const val = v.substring(index + 1, v.length) + obj[name] = val + } + }) + return obj +} + +/** + * @param {string} val + * @returns {string} + */ +export function html2Text(val) { + const div = document.createElement('div') + div.innerHTML = val + return div.textContent || div.innerText +} + +/** + * Merges two objects, giving the last one precedence + * @param {Object} target + * @param {(Object|Array)} source + * @returns {Object} + */ +export function objectMerge(target, source) { + if (typeof target !== 'object') { + target = {} + } + if (Array.isArray(source)) { + return source.slice() + } + Object.keys(source).forEach(property => { + const sourceProperty = source[property] + if (typeof sourceProperty === 'object') { + target[property] = objectMerge(target[property], sourceProperty) + } else { + target[property] = sourceProperty + } + }) + return target +} + +/** + * @param {HTMLElement} element + * @param {string} className + */ +export function toggleClass(element, className) { + if (!element || !className) { + return + } + let classString = element.className + const nameIndex = classString.indexOf(className) + if (nameIndex === -1) { + classString += '' + className + } else { + classString = + classString.substr(0, nameIndex) + + classString.substr(nameIndex + className.length) + } + element.className = classString +} + +/** + * @param {string} type + * @returns {Date} + */ +export function getTime(type) { + if (type === 'start') { + return new Date().getTime() - 3600 * 1000 * 24 * 90 + } else { + return new Date(new Date().toDateString()) + } +} + +/** + * @param {Function} func + * @param {number} wait + * @param {boolean} immediate + * @return {*} + */ +export function debounce(func, wait, immediate) { + let timeout, args, context, timestamp, result + + const later = function() { + // 据上一次触发时间间隔 + const last = +new Date() - timestamp + + // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait + if (last < wait && last > 0) { + timeout = setTimeout(later, wait - last) + } else { + timeout = null + // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用 + if (!immediate) { + result = func.apply(context, args) + if (!timeout) context = args = null + } + } + } + + return function(...args) { + context = this + timestamp = +new Date() + const callNow = immediate && !timeout + // 如果延时不存在,重新设定延时 + if (!timeout) timeout = setTimeout(later, wait) + if (callNow) { + result = func.apply(context, args) + context = args = null + } + + return result + } +} + +/** + * This is just a simple version of deep copy + * Has a lot of edge cases bug + * If you want to use a perfect deep copy, use lodash's _.cloneDeep + * @param {Object} source + * @returns {Object} + */ +export function deepClone(source) { + if (!source && typeof source !== 'object') { + throw new Error('error arguments', 'deepClone') + } + const targetObj = source.constructor === Array ? [] : {} + Object.keys(source).forEach(keys => { + if (source[keys] && typeof source[keys] === 'object') { + targetObj[keys] = deepClone(source[keys]) + } else { + targetObj[keys] = source[keys] + } + }) + return targetObj +} + +/** + * @param {Array} arr + * @returns {Array} + */ +export function uniqueArr(arr) { + return Array.from(new Set(arr)) +} + +/** + * @returns {string} + */ +export function createUniqueString() { + const timestamp = +new Date() + '' + const randomNum = parseInt((1 + Math.random()) * 65536) + '' + return (+(randomNum + timestamp)).toString(32) +} + +/** + * Check if an element has a class + * @param {HTMLElement} elm + * @param {string} cls + * @returns {boolean} + */ +export function hasClass(ele, cls) { + return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')) +} + +/** + * Add class to element + * @param {HTMLElement} elm + * @param {string} cls + */ +export function addClass(ele, cls) { + if (!hasClass(ele, cls)) ele.className += ' ' + cls +} + +/** + * Remove class from element + * @param {HTMLElement} elm + * @param {string} cls + */ +export function removeClass(ele, cls) { + if (hasClass(ele, cls)) { + const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)') + ele.className = ele.className.replace(reg, ' ') + } +} + +export function makeMap(str, expectsLowerCase) { + const map = Object.create(null) + const list = str.split(',') + for (let i = 0; i < list.length; i++) { + map[list[i]] = true + } + return expectsLowerCase + ? val => map[val.toLowerCase()] + : val => map[val] +} + +export const exportDefault = 'export default ' + +export const beautifierConf = { + html: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'separate', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: false, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + }, + js: { + indent_size: '2', + indent_char: ' ', + max_preserve_newlines: '-1', + preserve_newlines: false, + keep_array_indentation: false, + break_chained_methods: false, + indent_scripts: 'normal', + brace_style: 'end-expand', + space_before_conditional: true, + unescape_strings: false, + jslint_happy: true, + end_with_newline: true, + wrap_line_length: '110', + indent_inner_html: true, + comma_first: false, + e4x: true, + indent_empty_lines: true + } +} + +// 首字母大小 +export function titleCase(str) { + return str.replace(/( |^)[a-z]/g, L => L.toUpperCase()) +} + +// 下划转驼峰 +export function camelCase(str) { + return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase()) +} + +export function isNumberStr(str) { + return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str) +} + diff --git a/zhi-admin-ui/src/utils/jsencrypt.js b/zhi-admin-ui/src/utils/jsencrypt.js new file mode 100644 index 0000000..78d9523 --- /dev/null +++ b/zhi-admin-ui/src/utils/jsencrypt.js @@ -0,0 +1,30 @@ +import JSEncrypt from 'jsencrypt/bin/jsencrypt.min' + +// 密钥对生成 http://web.chacuo.net/netrsakeypair + +const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' + + 'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==' + +const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' + + '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' + + 'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' + + 'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' + + 'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' + + 'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' + + 'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' + + 'UP8iWi1Qw0Y=' + +// 加密 +export function encrypt(txt) { + const encryptor = new JSEncrypt() + encryptor.setPublicKey(publicKey) // 设置公钥 + return encryptor.encrypt(txt) // 对数据进行加密 +} + +// 解密 +export function decrypt(txt) { + const encryptor = new JSEncrypt() + encryptor.setPrivateKey(privateKey) // 设置私钥 + return encryptor.decrypt(txt) // 对数据进行解密 +} + diff --git a/zhi-admin-ui/src/utils/permission.js b/zhi-admin-ui/src/utils/permission.js new file mode 100644 index 0000000..bd4c066 --- /dev/null +++ b/zhi-admin-ui/src/utils/permission.js @@ -0,0 +1,51 @@ +import store from '@/store' + +/** + * 字符权限校验 + * @param {Array} value 校验值 + * @returns {Boolean} + */ +export function checkPermi(value) { + if (value && value instanceof Array && value.length > 0) { + const permissions = store.getters && store.getters.permissions + const permissionDatas = value + const all_permission = "*:*:*"; + + const hasPermission = permissions.some(permission => { + return all_permission === permission || permissionDatas.includes(permission) + }) + + if (!hasPermission) { + return false + } + return true + } else { + console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`) + return false + } +} + +/** + * 角色权限校验 + * @param {Array} value 校验值 + * @returns {Boolean} + */ +export function checkRole(value) { + if (value && value instanceof Array && value.length > 0) { + const roles = store.getters && store.getters.roles + const permissionRoles = value + const super_admin = "admin"; + + const hasRole = roles.some(role => { + return super_admin === role || permissionRoles.includes(role) + }) + + if (!hasRole) { + return false + } + return true + } else { + console.error(`need roles! Like checkRole="['admin','editor']"`) + return false + } +} diff --git a/zhi-admin-ui/src/utils/request.js b/zhi-admin-ui/src/utils/request.js new file mode 100644 index 0000000..f94fa0e --- /dev/null +++ b/zhi-admin-ui/src/utils/request.js @@ -0,0 +1,148 @@ +import axios from 'axios' +import { Notification, MessageBox, Message, Loading } from 'element-ui' +import store from '@/store' +import { getToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { tansParams, blobValidate } from "@/utils/ruoyi"; +import cache from '@/plugins/cache' +import { saveAs } from 'file-saver' + +let downloadLoadingInstance; +// 是否显示重新登录 +export let isRelogin = { show: false }; + +axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' +// 对应国际化资源文件后缀 +axios.defaults.headers['Content-Language'] = 'zh_CN' +// 创建axios实例 +const service = axios.create({ + // axios中请求配置有baseURL选项,表示请求URL公共部分 + baseURL: process.env.VUE_APP_BASE_API, + // 超时 + timeout: 10000 +}) + +// request拦截器 +service.interceptors.request.use(config => { + // 是否需要设置 token + const isToken = (config.headers || {}).isToken === false + // 是否需要防止数据重复提交 + const isRepeatSubmit = (config.headers || {}).repeatSubmit === false + if (getToken() && !isToken) { + config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 + } + // get请求映射params参数 + if (config.method === 'get' && config.params) { + let url = config.url + '?' + tansParams(config.params); + url = url.slice(0, -1); + config.params = {}; + config.url = url; + } + if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { + const requestObj = { + url: config.url, + data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, + time: new Date().getTime() + } + const sessionObj = cache.session.getJSON('sessionObj') + if (sessionObj === undefined || sessionObj === null || sessionObj === '') { + cache.session.setJSON('sessionObj', requestObj) + } else { + const s_url = sessionObj.url; // 请求地址 + const s_data = sessionObj.data; // 请求数据 + const s_time = sessionObj.time; // 请求时间 + const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交 + if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { + const message = '数据正在处理,请勿重复提交'; + console.warn(`[${s_url}]: ` + message) + return Promise.reject(new Error(message)) + } else { + cache.session.setJSON('sessionObj', requestObj) + } + } + } + return config +}, error => { + console.log(error) + Promise.reject(error) +}) + +// 响应拦截器 +service.interceptors.response.use(res => { + // 未设置状态码则默认成功状态 + const code = res.data.code || 200; + // 获取错误信息 + const msg = errorCode[code] || res.data.msg || errorCode['default'] + // 二进制数据则直接返回 + if(res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer'){ + return res.data + } + if (code === 401) { + if (!isRelogin.show) { + isRelogin.show = true; + MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => { + isRelogin.show = false; + store.dispatch('LogOut').then(() => { + location.href = process.env.VUE_APP_CONTEXT_PATH + "index"; + }) + }).catch(() => { + isRelogin.show = false; + }); + } + return Promise.reject('无效的会话,或者会话已过期,请重新登录。') + } else if (code === 500) { + Message({ message: msg, type: 'error' }) + return Promise.reject(new Error(msg)) + } else if (code === 601) { + Message({ message: msg, type: 'warning' }) + return Promise.reject('error') + } else if (code !== 200) { + Notification.error({ title: msg }) + return Promise.reject('error') + } else { + return res.data + } + }, + error => { + console.log('err' + error) + let { message } = error; + if (message == "Network Error") { + message = "后端接口连接异常"; + } else if (message.includes("timeout")) { + message = "系统接口请求超时"; + } else if (message.includes("Request failed with status code")) { + message = "系统接口" + message.substr(message.length - 3) + "异常"; + } + Message({ message: message, type: 'error', duration: 5 * 1000 }) + return Promise.reject(error) + } +) + +// 通用下载方法 +export function download(url, params, filename, config) { + downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) + return service.post(url, params, { + transformRequest: [(params) => { return tansParams(params) }], + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + responseType: 'blob', + ...config + }).then(async (data) => { + const isLogin = await blobValidate(data); + if (isLogin) { + const blob = new Blob([data]) + saveAs(blob, filename) + } else { + const resText = await data.text(); + const rspObj = JSON.parse(resText); + const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] + Message.error(errMsg); + } + downloadLoadingInstance.close(); + }).catch((r) => { + console.error(r) + Message.error('下载文件出现错误,请联系管理员!') + downloadLoadingInstance.close(); + }) +} + +export default service diff --git a/zhi-admin-ui/src/utils/ruoyi.js b/zhi-admin-ui/src/utils/ruoyi.js new file mode 100644 index 0000000..243c4c7 --- /dev/null +++ b/zhi-admin-ui/src/utils/ruoyi.js @@ -0,0 +1,239 @@ + + +/** + * 通用js方法封装处理 + * Copyright (c) 2019 ruoyi + */ + +// 日期格式化 +export function parseTime(time, pattern) { + if (arguments.length === 0 || !time) { + return null + } + const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'object') { + date = time + } else { + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { + time = parseInt(time) + } else if (typeof time === 'string') { + time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), ''); + } + if ((typeof time === 'number') && (time.toString().length === 10)) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + // Note: getDay() returns 0 on Sunday + if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} + +// 表单重置 +export function resetForm(refName) { + if (this.$refs[refName]) { + this.$refs[refName].resetFields(); + } +} + +// 添加日期范围 +export function addDateRange(params, dateRange, propName) { + let search = params; + search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {}; + dateRange = Array.isArray(dateRange) ? dateRange : []; + if (typeof (propName) === 'undefined') { + search.params['beginTime'] = dateRange[0]; + search.params['endTime'] = dateRange[1]; + } else { + search.params['begin' + propName] = dateRange[0]; + search.params['end' + propName] = dateRange[1]; + } + return search; +} + +// 回显数据字典 +export function selectDictLabel(datas, value) { + if (value === undefined) { + return ""; + } + var actions = []; + Object.keys(datas).some((key) => { + if (datas[key].value == ('' + value)) { + actions.push(datas[key].label); + return true; + } + }) + if (actions.length === 0) { + actions.push(value); + } + return actions.join(''); +} + +// 回显数据字典(字符串、数组) +export function selectDictLabels(datas, value, separator) { + if (value === undefined || value.length ===0) { + return ""; + } + if (Array.isArray(value)) { + value = value.join(","); + } + var actions = []; + var currentSeparator = undefined === separator ? "," : separator; + var temp = value.split(currentSeparator); + Object.keys(value.split(currentSeparator)).some((val) => { + var match = false; + Object.keys(datas).some((key) => { + if (datas[key].value == ('' + temp[val])) { + actions.push(datas[key].label + currentSeparator); + match = true; + } + }) + if (!match) { + actions.push(temp[val] + currentSeparator); + } + }) + return actions.join('').substring(0, actions.join('').length - 1); +} + +// 字符串格式化(%s ) +export function sprintf(str) { + var args = arguments, flag = true, i = 1; + str = str.replace(/%s/g, function () { + var arg = args[i++]; + if (typeof arg === 'undefined') { + flag = false; + return ''; + } + return arg; + }); + return flag ? str : ''; +} + +// 转换字符串,undefined,null等转化为"" +export function parseStrEmpty(str) { + if (!str || str == "undefined" || str == "null") { + return ""; + } + return str; +} + +// 数据合并 +export function mergeRecursive(source, target) { + for (var p in target) { + try { + if (target[p].constructor == Object) { + source[p] = mergeRecursive(source[p], target[p]); + } else { + source[p] = target[p]; + } + } catch (e) { + source[p] = target[p]; + } + } + return source; +}; + +/** + * 构造树型结构数据 + * @param {*} data 数据源 + * @param {*} id id字段 默认 'id' + * @param {*} parentId 父节点字段 默认 'parentId' + * @param {*} children 孩子节点字段 默认 'children' + */ +export function handleTree(data, id, parentId, children) { + let config = { + id: id || 'id', + parentId: parentId || 'parentId', + childrenList: children || 'children' + }; + + var childrenListMap = {}; + var nodeIds = {}; + var tree = []; + + for (let d of data) { + let parentId = d[config.parentId]; + if (childrenListMap[parentId] == null) { + childrenListMap[parentId] = []; + } + nodeIds[d[config.id]] = d; + childrenListMap[parentId].push(d); + } + + for (let d of data) { + let parentId = d[config.parentId]; + if (nodeIds[parentId] == null) { + tree.push(d); + } + } + + for (let t of tree) { + adaptToChildrenList(t); + } + + function adaptToChildrenList(o) { + if (childrenListMap[o[config.id]] !== null) { + o[config.childrenList] = childrenListMap[o[config.id]]; + } + if (o[config.childrenList]) { + for (let c of o[config.childrenList]) { + adaptToChildrenList(c); + } + } + } + return tree; +} + +/** +* 参数处理 +* @param {*} params 参数 +*/ +export function tansParams(params) { + let result = '' + for (const propName of Object.keys(params)) { + const value = params[propName]; + var part = encodeURIComponent(propName) + "="; + if (value !== null && value !== "" && typeof (value) !== "undefined") { + if (typeof value === 'object') { + for (const key of Object.keys(value)) { + if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { + let params = propName + '[' + key + ']'; + var subPart = encodeURIComponent(params) + "="; + result += subPart + encodeURIComponent(value[key]) + "&"; + } + } + } else { + result += part + encodeURIComponent(value) + "&"; + } + } + } + return result +} + +// 验证是否为blob格式 +export async function blobValidate(data) { + try { + const text = await data.text(); + JSON.parse(text); + return false; + } catch (error) { + return true; + } +} diff --git a/zhi-admin-ui/src/utils/scroll-to.js b/zhi-admin-ui/src/utils/scroll-to.js new file mode 100644 index 0000000..c5d8e04 --- /dev/null +++ b/zhi-admin-ui/src/utils/scroll-to.js @@ -0,0 +1,58 @@ +Math.easeInOutQuad = function(t, b, c, d) { + t /= d / 2 + if (t < 1) { + return c / 2 * t * t + b + } + t-- + return -c / 2 * (t * (t - 2) - 1) + b +} + +// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts +var requestAnimFrame = (function() { + return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) } +})() + +/** + * Because it's so fucking difficult to detect the scrolling element, just move them all + * @param {number} amount + */ +function move(amount) { + document.documentElement.scrollTop = amount + document.body.parentNode.scrollTop = amount + document.body.scrollTop = amount +} + +function position() { + return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop +} + +/** + * @param {number} to + * @param {number} duration + * @param {Function} callback + */ +export function scrollTo(to, duration, callback) { + const start = position() + const change = to - start + const increment = 20 + let currentTime = 0 + duration = (typeof (duration) === 'undefined') ? 500 : duration + var animateScroll = function() { + // increment the time + currentTime += increment + // find the value with the quadratic in-out easing function + var val = Math.easeInOutQuad(currentTime, start, change, duration) + // move the document.body + move(val) + // do the animation unless its over + if (currentTime < duration) { + requestAnimFrame(animateScroll) + } else { + if (callback && typeof (callback) === 'function') { + // the animation is done so lets callback + callback() + } + } + } + animateScroll() +} diff --git a/zhi-admin-ui/src/utils/validate.js b/zhi-admin-ui/src/utils/validate.js new file mode 100644 index 0000000..adfa254 --- /dev/null +++ b/zhi-admin-ui/src/utils/validate.js @@ -0,0 +1,83 @@ +/** + * @param {string} path + * @returns {Boolean} + */ +export function isExternal(path) { + return /^(https?:|mailto:|tel:)/.test(path) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validUsername(str) { + const valid_map = ['admin', 'editor'] + return valid_map.indexOf(str.trim()) >= 0 +} + +/** + * @param {string} url + * @returns {Boolean} + */ +export function validURL(url) { + const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/ + return reg.test(url) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validLowerCase(str) { + const reg = /^[a-z]+$/ + return reg.test(str) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validUpperCase(str) { + const reg = /^[A-Z]+$/ + return reg.test(str) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function validAlphabets(str) { + const reg = /^[A-Za-z]+$/ + return reg.test(str) +} + +/** + * @param {string} email + * @returns {Boolean} + */ +export function validEmail(email) { + const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + return reg.test(email) +} + +/** + * @param {string} str + * @returns {Boolean} + */ +export function isString(str) { + if (typeof str === 'string' || str instanceof String) { + return true + } + return false +} + +/** + * @param {Array} arg + * @returns {Boolean} + */ +export function isArray(arg) { + if (typeof Array.isArray === 'undefined') { + return Object.prototype.toString.call(arg) === '[object Array]' + } + return Array.isArray(arg) +} diff --git a/zhi-admin-ui/src/views/about/About.vue b/zhi-admin-ui/src/views/about/About.vue new file mode 100644 index 0000000..5a0e5d5 --- /dev/null +++ b/zhi-admin-ui/src/views/about/About.vue @@ -0,0 +1,154 @@ + + + + + diff --git a/zhi-admin-ui/src/views/album/album/Album.vue b/zhi-admin-ui/src/views/album/album/Album.vue new file mode 100644 index 0000000..85d023c --- /dev/null +++ b/zhi-admin-ui/src/views/album/album/Album.vue @@ -0,0 +1,363 @@ + + + + + diff --git a/zhi-admin-ui/src/views/album/album/Photo.vue b/zhi-admin-ui/src/views/album/album/Photo.vue new file mode 100644 index 0000000..2c4fdb0 --- /dev/null +++ b/zhi-admin-ui/src/views/album/album/Photo.vue @@ -0,0 +1,530 @@ + + + + + diff --git a/zhi-admin-ui/src/views/album/album/new/SPhoto.vue b/zhi-admin-ui/src/views/album/album/new/SPhoto.vue new file mode 100644 index 0000000..c9cc704 --- /dev/null +++ b/zhi-admin-ui/src/views/album/album/new/SPhoto.vue @@ -0,0 +1,340 @@ + + + diff --git a/zhi-admin-ui/src/views/album/album/new/index.vue b/zhi-admin-ui/src/views/album/album/new/index.vue new file mode 100644 index 0000000..ff48315 --- /dev/null +++ b/zhi-admin-ui/src/views/album/album/new/index.vue @@ -0,0 +1,307 @@ + + + diff --git a/zhi-admin-ui/src/views/article/article/index.vue b/zhi-admin-ui/src/views/article/article/index.vue new file mode 100644 index 0000000..6a6258a --- /dev/null +++ b/zhi-admin-ui/src/views/article/article/index.vue @@ -0,0 +1,572 @@ + + + + + diff --git a/zhi-admin-ui/src/views/article/articleList/index.vue b/zhi-admin-ui/src/views/article/articleList/index.vue new file mode 100644 index 0000000..15467c5 --- /dev/null +++ b/zhi-admin-ui/src/views/article/articleList/index.vue @@ -0,0 +1,628 @@ + + + + + + diff --git a/zhi-admin-ui/src/views/category/category/index.vue b/zhi-admin-ui/src/views/category/category/index.vue new file mode 100644 index 0000000..3cd6c16 --- /dev/null +++ b/zhi-admin-ui/src/views/category/category/index.vue @@ -0,0 +1,278 @@ + + + diff --git a/zhi-admin-ui/src/views/comment/comment/index.vue b/zhi-admin-ui/src/views/comment/comment/index.vue new file mode 100644 index 0000000..9701390 --- /dev/null +++ b/zhi-admin-ui/src/views/comment/comment/index.vue @@ -0,0 +1,449 @@ + + + diff --git a/zhi-admin-ui/src/views/components/icons/element-icons.js b/zhi-admin-ui/src/views/components/icons/element-icons.js new file mode 100644 index 0000000..9ea4d63 --- /dev/null +++ b/zhi-admin-ui/src/views/components/icons/element-icons.js @@ -0,0 +1,3 @@ +const elementIcons = ['platform-eleme', 'eleme', 'delete-solid', 'delete', 's-tools', 'setting', 'user-solid', 'user', 'phone', 'phone-outline', 'more', 'more-outline', 'star-on', 'star-off', 's-goods', 'goods', 'warning', 'warning-outline', 'question', 'info', 'remove', 'circle-plus', 'success', 'error', 'zoom-in', 'zoom-out', 'remove-outline', 'circle-plus-outline', 'circle-check', 'circle-close', 's-help', 'help', 'minus', 'plus', 'check', 'close', 'picture', 'picture-outline', 'picture-outline-round', 'upload', 'upload2', 'download', 'camera-solid', 'camera', 'video-camera-solid', 'video-camera', 'message-solid', 'bell', 's-cooperation', 's-order', 's-platform', 's-fold', 's-unfold', 's-operation', 's-promotion', 's-home', 's-release', 's-ticket', 's-management', 's-open', 's-shop', 's-marketing', 's-flag', 's-comment', 's-finance', 's-claim', 's-custom', 's-opportunity', 's-data', 's-check', 's-grid', 'menu', 'share', 'd-caret', 'caret-left', 'caret-right', 'caret-bottom', 'caret-top', 'bottom-left', 'bottom-right', 'back', 'right', 'bottom', 'top', 'top-left', 'top-right', 'arrow-left', 'arrow-right', 'arrow-down', 'arrow-up', 'd-arrow-left', 'd-arrow-right', 'video-pause', 'video-play', 'refresh', 'refresh-right', 'refresh-left', 'finished', 'sort', 'sort-up', 'sort-down', 'rank', 'loading', 'view', 'c-scale-to-original', 'date', 'edit', 'edit-outline', 'folder', 'folder-opened', 'folder-add', 'folder-remove', 'folder-delete', 'folder-checked', 'tickets', 'document-remove', 'document-delete', 'document-copy', 'document-checked', 'document', 'document-add', 'printer', 'paperclip', 'takeaway-box', 'search', 'monitor', 'attract', 'mobile', 'scissors', 'umbrella', 'headset', 'brush', 'mouse', 'coordinate', 'magic-stick', 'reading', 'data-line', 'data-board', 'pie-chart', 'data-analysis', 'collection-tag', 'film', 'suitcase', 'suitcase-1', 'receiving', 'collection', 'files', 'notebook-1', 'notebook-2', 'toilet-paper', 'office-building', 'school', 'table-lamp', 'house', 'no-smoking', 'smoking', 'shopping-cart-full', 'shopping-cart-1', 'shopping-cart-2', 'shopping-bag-1', 'shopping-bag-2', 'sold-out', 'sell', 'present', 'box', 'bank-card', 'money', 'coin', 'wallet', 'discount', 'price-tag', 'news', 'guide', 'male', 'female', 'thumb', 'cpu', 'link', 'connection', 'open', 'turn-off', 'set-up', 'chat-round', 'chat-line-round', 'chat-square', 'chat-dot-round', 'chat-dot-square', 'chat-line-square', 'message', 'postcard', 'position', 'turn-off-microphone', 'microphone', 'close-notification', 'bangzhu', 'time', 'odometer', 'crop', 'aim', 'switch-button', 'full-screen', 'copy-document', 'mic', 'stopwatch', 'medal-1', 'medal', 'trophy', 'trophy-1', 'first-aid-kit', 'discover', 'place', 'location', 'location-outline', 'location-information', 'add-location', 'delete-location', 'map-location', 'alarm-clock', 'timer', 'watch-1', 'watch', 'lock', 'unlock', 'key', 'service', 'mobile-phone', 'bicycle', 'truck', 'ship', 'basketball', 'football', 'soccer', 'baseball', 'wind-power', 'light-rain', 'lightning', 'heavy-rain', 'sunrise', 'sunrise-1', 'sunset', 'sunny', 'cloudy', 'partly-cloudy', 'cloudy-and-sunny', 'moon', 'moon-night', 'dish', 'dish-1', 'food', 'chicken', 'fork-spoon', 'knife-fork', 'burger', 'tableware', 'sugar', 'dessert', 'ice-cream', 'hot-water', 'water-cup', 'coffee-cup', 'cold-drink', 'goblet', 'goblet-full', 'goblet-square', 'goblet-square-full', 'refrigerator', 'grape', 'watermelon', 'cherry', 'apple', 'pear', 'orange', 'coffee', 'ice-tea', 'ice-drink', 'milk-tea', 'potato-strips', 'lollipop', 'ice-cream-square', 'ice-cream-round'] + +export default elementIcons diff --git a/zhi-admin-ui/src/views/components/icons/index.vue b/zhi-admin-ui/src/views/components/icons/index.vue new file mode 100644 index 0000000..d3c9a71 --- /dev/null +++ b/zhi-admin-ui/src/views/components/icons/index.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/zhi-admin-ui/src/views/components/icons/svg-icons.js b/zhi-admin-ui/src/views/components/icons/svg-icons.js new file mode 100644 index 0000000..724cd8e --- /dev/null +++ b/zhi-admin-ui/src/views/components/icons/svg-icons.js @@ -0,0 +1,10 @@ +const req = require.context('../../../assets/icons/svg', false, /\.svg$/) +const requireAll = requireContext => requireContext.keys() + +const re = /\.\/(.*)\.svg/ + +const svgIcons = requireAll(req).map(i => { + return i.match(re)[1] +}) + +export default svgIcons diff --git a/zhi-admin-ui/src/views/dashboard/BarChart.vue b/zhi-admin-ui/src/views/dashboard/BarChart.vue new file mode 100644 index 0000000..be0af34 --- /dev/null +++ b/zhi-admin-ui/src/views/dashboard/BarChart.vue @@ -0,0 +1,102 @@ + + + diff --git a/zhi-admin-ui/src/views/dashboard/LineChart.vue b/zhi-admin-ui/src/views/dashboard/LineChart.vue new file mode 100644 index 0000000..e654168 --- /dev/null +++ b/zhi-admin-ui/src/views/dashboard/LineChart.vue @@ -0,0 +1,135 @@ + + + diff --git a/zhi-admin-ui/src/views/dashboard/PanelGroup.vue b/zhi-admin-ui/src/views/dashboard/PanelGroup.vue new file mode 100644 index 0000000..1a1081f --- /dev/null +++ b/zhi-admin-ui/src/views/dashboard/PanelGroup.vue @@ -0,0 +1,181 @@ + + + + + diff --git a/zhi-admin-ui/src/views/dashboard/PieChart.vue b/zhi-admin-ui/src/views/dashboard/PieChart.vue new file mode 100644 index 0000000..4d2ef32 --- /dev/null +++ b/zhi-admin-ui/src/views/dashboard/PieChart.vue @@ -0,0 +1,79 @@ + + + diff --git a/zhi-admin-ui/src/views/dashboard/RaddarChart.vue b/zhi-admin-ui/src/views/dashboard/RaddarChart.vue new file mode 100644 index 0000000..6823af3 --- /dev/null +++ b/zhi-admin-ui/src/views/dashboard/RaddarChart.vue @@ -0,0 +1,116 @@ + + + diff --git a/zhi-admin-ui/src/views/dashboard/mixins/resize.js b/zhi-admin-ui/src/views/dashboard/mixins/resize.js new file mode 100644 index 0000000..b1e76e9 --- /dev/null +++ b/zhi-admin-ui/src/views/dashboard/mixins/resize.js @@ -0,0 +1,56 @@ +import { debounce } from '@/utils' + +export default { + data() { + return { + $_sidebarElm: null, + $_resizeHandler: null + } + }, + mounted() { + this.initListener() + }, + activated() { + if (!this.$_resizeHandler) { + // avoid duplication init + this.initListener() + } + + // when keep-alive chart activated, auto resize + this.resize() + }, + beforeDestroy() { + this.destroyListener() + }, + deactivated() { + this.destroyListener() + }, + methods: { + // use $_ for mixins properties + // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential + $_sidebarResizeHandler(e) { + if (e.propertyName === 'width') { + this.$_resizeHandler() + } + }, + initListener() { + this.$_resizeHandler = debounce(() => { + this.resize() + }, 100) + window.addEventListener('resize', this.$_resizeHandler) + + this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] + this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) + }, + destroyListener() { + window.removeEventListener('resize', this.$_resizeHandler) + this.$_resizeHandler = null + + this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) + }, + resize() { + const { chart } = this + chart && chart.resize() + } + } +} diff --git a/zhi-admin-ui/src/views/demo/demo/index.vue b/zhi-admin-ui/src/views/demo/demo/index.vue new file mode 100644 index 0000000..65387c9 --- /dev/null +++ b/zhi-admin-ui/src/views/demo/demo/index.vue @@ -0,0 +1,431 @@ + + + diff --git a/zhi-admin-ui/src/views/demo/tree/index.vue b/zhi-admin-ui/src/views/demo/tree/index.vue new file mode 100644 index 0000000..6cfa7f2 --- /dev/null +++ b/zhi-admin-ui/src/views/demo/tree/index.vue @@ -0,0 +1,313 @@ + + + diff --git a/zhi-admin-ui/src/views/error/401.vue b/zhi-admin-ui/src/views/error/401.vue new file mode 100644 index 0000000..448b6ec --- /dev/null +++ b/zhi-admin-ui/src/views/error/401.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/zhi-admin-ui/src/views/error/404.vue b/zhi-admin-ui/src/views/error/404.vue new file mode 100644 index 0000000..96f075c --- /dev/null +++ b/zhi-admin-ui/src/views/error/404.vue @@ -0,0 +1,233 @@ + + + + + diff --git a/zhi-admin-ui/src/views/friendLink/friendLink/index.vue b/zhi-admin-ui/src/views/friendLink/friendLink/index.vue new file mode 100644 index 0000000..5a58183 --- /dev/null +++ b/zhi-admin-ui/src/views/friendLink/friendLink/index.vue @@ -0,0 +1,319 @@ + + + diff --git a/zhi-admin-ui/src/views/index.vue b/zhi-admin-ui/src/views/index.vue new file mode 100644 index 0000000..3d724c8 --- /dev/null +++ b/zhi-admin-ui/src/views/index.vue @@ -0,0 +1,177 @@ + + + + diff --git a/zhi-admin-ui/src/views/index_v1.vue b/zhi-admin-ui/src/views/index_v1.vue new file mode 100644 index 0000000..d2d2ec6 --- /dev/null +++ b/zhi-admin-ui/src/views/index_v1.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/zhi-admin-ui/src/views/login.vue b/zhi-admin-ui/src/views/login.vue new file mode 100644 index 0000000..9709373 --- /dev/null +++ b/zhi-admin-ui/src/views/login.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/zhi-admin-ui/src/views/message/message/index.vue b/zhi-admin-ui/src/views/message/message/index.vue new file mode 100644 index 0000000..ba8b61a --- /dev/null +++ b/zhi-admin-ui/src/views/message/message/index.vue @@ -0,0 +1,399 @@ + + + diff --git a/zhi-admin-ui/src/views/monitor/cache/index.vue b/zhi-admin-ui/src/views/monitor/cache/index.vue new file mode 100644 index 0000000..8a0275c --- /dev/null +++ b/zhi-admin-ui/src/views/monitor/cache/index.vue @@ -0,0 +1,146 @@ + + + diff --git a/zhi-admin-ui/src/views/monitor/cache/list.vue b/zhi-admin-ui/src/views/monitor/cache/list.vue new file mode 100644 index 0000000..94307ab --- /dev/null +++ b/zhi-admin-ui/src/views/monitor/cache/list.vue @@ -0,0 +1,241 @@ + + + diff --git a/zhi-admin-ui/src/views/monitor/logininfor/index.vue b/zhi-admin-ui/src/views/monitor/logininfor/index.vue new file mode 100644 index 0000000..8a9b17a --- /dev/null +++ b/zhi-admin-ui/src/views/monitor/logininfor/index.vue @@ -0,0 +1,245 @@ + + + + diff --git a/zhi-admin-ui/src/views/monitor/online/index.vue b/zhi-admin-ui/src/views/monitor/online/index.vue new file mode 100644 index 0000000..ad613c9 --- /dev/null +++ b/zhi-admin-ui/src/views/monitor/online/index.vue @@ -0,0 +1,122 @@ + + + + diff --git a/zhi-admin-ui/src/views/monitor/operlog/index.vue b/zhi-admin-ui/src/views/monitor/operlog/index.vue new file mode 100644 index 0000000..c1b5377 --- /dev/null +++ b/zhi-admin-ui/src/views/monitor/operlog/index.vue @@ -0,0 +1,305 @@ + + + + diff --git a/zhi-admin-ui/src/views/monitor/xxljob/index.vue b/zhi-admin-ui/src/views/monitor/xxljob/index.vue new file mode 100644 index 0000000..7167b48 --- /dev/null +++ b/zhi-admin-ui/src/views/monitor/xxljob/index.vue @@ -0,0 +1,15 @@ + + diff --git a/zhi-admin-ui/src/views/page/index.vue b/zhi-admin-ui/src/views/page/index.vue new file mode 100644 index 0000000..39e945b --- /dev/null +++ b/zhi-admin-ui/src/views/page/index.vue @@ -0,0 +1,302 @@ + + + diff --git a/zhi-admin-ui/src/views/redirect.vue b/zhi-admin-ui/src/views/redirect.vue new file mode 100644 index 0000000..db4c1d6 --- /dev/null +++ b/zhi-admin-ui/src/views/redirect.vue @@ -0,0 +1,12 @@ + diff --git a/zhi-admin-ui/src/views/register.vue b/zhi-admin-ui/src/views/register.vue new file mode 100644 index 0000000..1797599 --- /dev/null +++ b/zhi-admin-ui/src/views/register.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/zhi-admin-ui/src/views/system/config/index.vue b/zhi-admin-ui/src/views/system/config/index.vue new file mode 100644 index 0000000..f580b98 --- /dev/null +++ b/zhi-admin-ui/src/views/system/config/index.vue @@ -0,0 +1,343 @@ + + + diff --git a/zhi-admin-ui/src/views/system/dept/index.vue b/zhi-admin-ui/src/views/system/dept/index.vue new file mode 100644 index 0000000..e502b4e --- /dev/null +++ b/zhi-admin-ui/src/views/system/dept/index.vue @@ -0,0 +1,340 @@ + + + diff --git a/zhi-admin-ui/src/views/system/dict/data.vue b/zhi-admin-ui/src/views/system/dict/data.vue new file mode 100644 index 0000000..c36cffc --- /dev/null +++ b/zhi-admin-ui/src/views/system/dict/data.vue @@ -0,0 +1,402 @@ + + + diff --git a/zhi-admin-ui/src/views/system/dict/index.vue b/zhi-admin-ui/src/views/system/dict/index.vue new file mode 100644 index 0000000..b6ed788 --- /dev/null +++ b/zhi-admin-ui/src/views/system/dict/index.vue @@ -0,0 +1,347 @@ + + + diff --git a/zhi-admin-ui/src/views/system/menu/index.vue b/zhi-admin-ui/src/views/system/menu/index.vue new file mode 100644 index 0000000..52eb8b9 --- /dev/null +++ b/zhi-admin-ui/src/views/system/menu/index.vue @@ -0,0 +1,453 @@ + + + diff --git a/zhi-admin-ui/src/views/system/notice/index.vue b/zhi-admin-ui/src/views/system/notice/index.vue new file mode 100644 index 0000000..19e25a0 --- /dev/null +++ b/zhi-admin-ui/src/views/system/notice/index.vue @@ -0,0 +1,312 @@ + + + \ No newline at end of file diff --git a/zhi-admin-ui/src/views/system/oss/config.vue b/zhi-admin-ui/src/views/system/oss/config.vue new file mode 100644 index 0000000..0120641 --- /dev/null +++ b/zhi-admin-ui/src/views/system/oss/config.vue @@ -0,0 +1,406 @@ + + + diff --git a/zhi-admin-ui/src/views/system/oss/index.vue b/zhi-admin-ui/src/views/system/oss/index.vue new file mode 100644 index 0000000..9f8557c --- /dev/null +++ b/zhi-admin-ui/src/views/system/oss/index.vue @@ -0,0 +1,414 @@ + + + diff --git a/zhi-admin-ui/src/views/system/post/index.vue b/zhi-admin-ui/src/views/system/post/index.vue new file mode 100644 index 0000000..444bf63 --- /dev/null +++ b/zhi-admin-ui/src/views/system/post/index.vue @@ -0,0 +1,309 @@ + + + diff --git a/zhi-admin-ui/src/views/system/role/authUser.vue b/zhi-admin-ui/src/views/system/role/authUser.vue new file mode 100644 index 0000000..147aa33 --- /dev/null +++ b/zhi-admin-ui/src/views/system/role/authUser.vue @@ -0,0 +1,199 @@ + + + \ No newline at end of file diff --git a/zhi-admin-ui/src/views/system/role/index.vue b/zhi-admin-ui/src/views/system/role/index.vue new file mode 100644 index 0000000..ca02f3a --- /dev/null +++ b/zhi-admin-ui/src/views/system/role/index.vue @@ -0,0 +1,606 @@ + + + + diff --git a/zhi-admin-ui/src/views/system/role/selectUser.vue b/zhi-admin-ui/src/views/system/role/selectUser.vue new file mode 100644 index 0000000..b2b072f --- /dev/null +++ b/zhi-admin-ui/src/views/system/role/selectUser.vue @@ -0,0 +1,138 @@ + + + diff --git a/zhi-admin-ui/src/views/system/user/authRole.vue b/zhi-admin-ui/src/views/system/user/authRole.vue new file mode 100644 index 0000000..7abe26a --- /dev/null +++ b/zhi-admin-ui/src/views/system/user/authRole.vue @@ -0,0 +1,117 @@ + + + diff --git a/zhi-admin-ui/src/views/system/user/index.vue b/zhi-admin-ui/src/views/system/user/index.vue new file mode 100644 index 0000000..b2120e6 --- /dev/null +++ b/zhi-admin-ui/src/views/system/user/index.vue @@ -0,0 +1,670 @@ + + + diff --git a/zhi-admin-ui/src/views/system/user/profile/index.vue b/zhi-admin-ui/src/views/system/user/profile/index.vue new file mode 100644 index 0000000..2cc7c2f --- /dev/null +++ b/zhi-admin-ui/src/views/system/user/profile/index.vue @@ -0,0 +1,91 @@ + + + diff --git a/zhi-admin-ui/src/views/system/user/profile/resetPwd.vue b/zhi-admin-ui/src/views/system/user/profile/resetPwd.vue new file mode 100644 index 0000000..64e8f8c --- /dev/null +++ b/zhi-admin-ui/src/views/system/user/profile/resetPwd.vue @@ -0,0 +1,68 @@ + + + diff --git a/zhi-admin-ui/src/views/system/user/profile/userAvatar.vue b/zhi-admin-ui/src/views/system/user/profile/userAvatar.vue new file mode 100644 index 0000000..18b23a4 --- /dev/null +++ b/zhi-admin-ui/src/views/system/user/profile/userAvatar.vue @@ -0,0 +1,190 @@ + + + + diff --git a/zhi-admin-ui/src/views/system/user/profile/userInfo.vue b/zhi-admin-ui/src/views/system/user/profile/userInfo.vue new file mode 100644 index 0000000..068b714 --- /dev/null +++ b/zhi-admin-ui/src/views/system/user/profile/userInfo.vue @@ -0,0 +1,75 @@ + + + diff --git a/zhi-admin-ui/src/views/tag/tag/index.vue b/zhi-admin-ui/src/views/tag/tag/index.vue new file mode 100644 index 0000000..17a43fb --- /dev/null +++ b/zhi-admin-ui/src/views/tag/tag/index.vue @@ -0,0 +1,279 @@ + + + diff --git a/zhi-admin-ui/src/views/talk/talk/index.vue b/zhi-admin-ui/src/views/talk/talk/index.vue new file mode 100644 index 0000000..28d2755 --- /dev/null +++ b/zhi-admin-ui/src/views/talk/talk/index.vue @@ -0,0 +1,199 @@ + + + + + diff --git a/zhi-admin-ui/src/views/talk/talkList/index.vue b/zhi-admin-ui/src/views/talk/talkList/index.vue new file mode 100644 index 0000000..cced271 --- /dev/null +++ b/zhi-admin-ui/src/views/talk/talkList/index.vue @@ -0,0 +1,255 @@ + + + + + diff --git a/zhi-admin-ui/src/views/tool/build/CodeTypeDialog.vue b/zhi-admin-ui/src/views/tool/build/CodeTypeDialog.vue new file mode 100644 index 0000000..b5c2e2e --- /dev/null +++ b/zhi-admin-ui/src/views/tool/build/CodeTypeDialog.vue @@ -0,0 +1,106 @@ + + diff --git a/zhi-admin-ui/src/views/tool/build/DraggableItem.vue b/zhi-admin-ui/src/views/tool/build/DraggableItem.vue new file mode 100644 index 0000000..e881778 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/build/DraggableItem.vue @@ -0,0 +1,100 @@ + diff --git a/zhi-admin-ui/src/views/tool/build/IconsDialog.vue b/zhi-admin-ui/src/views/tool/build/IconsDialog.vue new file mode 100644 index 0000000..958be50 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/build/IconsDialog.vue @@ -0,0 +1,123 @@ + + + diff --git a/zhi-admin-ui/src/views/tool/build/RightPanel.vue b/zhi-admin-ui/src/views/tool/build/RightPanel.vue new file mode 100644 index 0000000..c2760eb --- /dev/null +++ b/zhi-admin-ui/src/views/tool/build/RightPanel.vue @@ -0,0 +1,946 @@ + + + + + diff --git a/zhi-admin-ui/src/views/tool/build/TreeNodeDialog.vue b/zhi-admin-ui/src/views/tool/build/TreeNodeDialog.vue new file mode 100644 index 0000000..fa7f0b2 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/build/TreeNodeDialog.vue @@ -0,0 +1,149 @@ + + diff --git a/zhi-admin-ui/src/views/tool/build/index.vue b/zhi-admin-ui/src/views/tool/build/index.vue new file mode 100644 index 0000000..d679422 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/build/index.vue @@ -0,0 +1,783 @@ + + + + + diff --git a/zhi-admin-ui/src/views/tool/gen/basicInfoForm.vue b/zhi-admin-ui/src/views/tool/gen/basicInfoForm.vue new file mode 100644 index 0000000..7029529 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/gen/basicInfoForm.vue @@ -0,0 +1,60 @@ + + + diff --git a/zhi-admin-ui/src/views/tool/gen/editTable.vue b/zhi-admin-ui/src/views/tool/gen/editTable.vue new file mode 100644 index 0000000..f34327d --- /dev/null +++ b/zhi-admin-ui/src/views/tool/gen/editTable.vue @@ -0,0 +1,234 @@ + + + diff --git a/zhi-admin-ui/src/views/tool/gen/genInfoForm.vue b/zhi-admin-ui/src/views/tool/gen/genInfoForm.vue new file mode 100644 index 0000000..a597a95 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/gen/genInfoForm.vue @@ -0,0 +1,299 @@ + + + diff --git a/zhi-admin-ui/src/views/tool/gen/importTable.vue b/zhi-admin-ui/src/views/tool/gen/importTable.vue new file mode 100644 index 0000000..3ea9532 --- /dev/null +++ b/zhi-admin-ui/src/views/tool/gen/importTable.vue @@ -0,0 +1,120 @@ + + + diff --git a/zhi-admin-ui/src/views/tool/gen/index.vue b/zhi-admin-ui/src/views/tool/gen/index.vue new file mode 100644 index 0000000..66bd13f --- /dev/null +++ b/zhi-admin-ui/src/views/tool/gen/index.vue @@ -0,0 +1,348 @@ + + + diff --git a/zhi-admin-ui/src/views/website/index.vue b/zhi-admin-ui/src/views/website/index.vue new file mode 100644 index 0000000..02ab884 --- /dev/null +++ b/zhi-admin-ui/src/views/website/index.vue @@ -0,0 +1,292 @@ + + + + + diff --git a/zhi-admin-ui/vue.config.js b/zhi-admin-ui/vue.config.js new file mode 100644 index 0000000..209ac13 --- /dev/null +++ b/zhi-admin-ui/vue.config.js @@ -0,0 +1,136 @@ +'use strict' +const path = require('path') + +function resolve(dir) { + return path.join(__dirname, dir) +} + +const CompressionPlugin = require('compression-webpack-plugin') + +const name = process.env.VUE_APP_TITLE || 'zhi-water的博客' // 网页标题 + +const port = process.env.port || process.env.npm_config_port || 81 // 端口 + +// vue.config.js 配置说明 +//官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions +// 这里只列一部分,具体配置参考文档 +module.exports = { + // 部署生产环境和开发环境下的URL。 + // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上 + // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。 + publicPath: process.env.VUE_APP_CONTEXT_PATH, + // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist) + outputDir: 'dist', + // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下) + assetsDir: 'static', + // 是否开启eslint保存检测,有效值:ture | false | 'error' + lintOnSave: process.env.NODE_ENV === 'development', + // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。 + productionSourceMap: false, + // webpack-dev-server 相关配置 + devServer: { + host: '0.0.0.0', + port: port, + open: true, + proxy: { + // detail: https://cli.vuejs.org/config/#devserver-proxy + [process.env.VUE_APP_BASE_API]: { + target: `http://127.0.0.1:8080`, + changeOrigin: true, + pathRewrite: { + ['^' + process.env.VUE_APP_BASE_API]: '' + } + } + }, + disableHostCheck: true + }, + css: { + loaderOptions: { + sass: { + sassOptions: { outputStyle: "expanded" } + } + } + }, + configureWebpack: { + name: name, + resolve: { + alias: { + '@': resolve('src') + } + }, + plugins: [ + // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件 + new CompressionPlugin({ + cache: false, // 不启用文件缓存 + test: /\.(js|css|html)?$/i, // 压缩文件格式 + filename: '[path].gz[query]', // 压缩后的文件名 + algorithm: 'gzip', // 使用gzip压缩 + minRatio: 0.8 // 压缩率小于1才会压缩 + }) + ], + }, + chainWebpack(config) { + config.plugins.delete('preload') // TODO: need test + config.plugins.delete('prefetch') // TODO: need test + + // set svg-sprite-loader + config.module + .rule('svg') + .exclude.add(resolve('src/assets/icons')) + .end() + config.module + .rule('icons') + .test(/\.svg$/) + .include.add(resolve('src/assets/icons')) + .end() + .use('svg-sprite-loader') + .loader('svg-sprite-loader') + .options({ + symbolId: 'icon-[name]' + }) + .end() + + config + .when(process.env.NODE_ENV !== 'development', + config => { + config + .plugin('ScriptExtHtmlWebpackPlugin') + .after('html') + .use('script-ext-html-webpack-plugin', [{ + // `runtime` must same as runtimeChunk name. default is `runtime` + inline: /runtime\..*\.js$/ + }]) + .end() + config + .optimization.splitChunks({ + chunks: 'all', + cacheGroups: { + libs: { + name: 'chunk-libs', + test: /[\\/]node_modules[\\/]/, + priority: 10, + chunks: 'initial' // only package third parties that are initially dependent + }, + elementUI: { + name: 'chunk-elementUI', // split elementUI into a single package + priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app + test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm + }, + commons: { + name: 'chunk-commons', + test: resolve('src/components'), // can customize your rules + minChunks: 3, // minimum common number + priority: 5, + reuseExistingChunk: true + } + } + }) + config.optimization.runtimeChunk('single'), + { + from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件 + to: './' //到根目录下 + } + } + ) + } +} diff --git a/zhi-admin/Dockerfile b/zhi-admin/Dockerfile new file mode 100644 index 0000000..95335e3 --- /dev/null +++ b/zhi-admin/Dockerfile @@ -0,0 +1,23 @@ +FROM anapsix/alpine-java:8_server-jre_unlimited + +MAINTAINER Lion Li + +RUN mkdir -p /ruoyi/server/logs \ + /ruoyi/server/temp \ + /ruoyi/skywalking/agent + +WORKDIR /ruoyi/server + +ENV SERVER_PORT=8080 + +EXPOSE ${SERVER_PORT} + +ADD ./target/zhi-admin.jar ./app.jar + +ENTRYPOINT ["java", \ + "-Djava.security.egd=file:/dev/./urandom", \ + "-Dserver.port=${SERVER_PORT}", \ + # 应用名称 如果想区分集群节点监控 改成不同的名称即可 +# "-Dskywalking.agent.service_name=ruoyi-server", \ +# "-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar", \ + "-jar", "app.jar"] diff --git a/zhi-admin/pom.xml b/zhi-admin/pom.xml new file mode 100644 index 0000000..d028001 --- /dev/null +++ b/zhi-admin/pom.xml @@ -0,0 +1,157 @@ + + + + ruoyi-vue-plus + com.zhi + 4.4.0 + + 4.0.0 + jar + zhi-admin + + + web服务入口 + + + + + + + org.springframework.boot + spring-boot-devtools + true + + + + + com.mysql + mysql-connector-j + + + + + com.oracle.database.jdbc + ojdbc8 + + + + + org.postgresql + postgresql + + + + + com.microsoft.sqlserver + mssql-jdbc + + + + + com.zhi + zhi-framework + + + + com.zhi + zhi-system + + + + com.zhi + zhi-job + + + + com.zhi + zhi-oss + + + + + com.zhi + zhi-generator + + + + + org.apache.commons + commons-pool2 + + + + + com.xkcoding.justauth + justauth-spring-boot-starter + + + + + com.zhi + zhi-demo + + + + + com.zhi + zhi-myblog + + + + + + com.zhi + zhi-common + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + true + + + + + repackage + + + + + + org.apache.maven.plugins + maven-war-plugin + 3.2.2 + + false + ${project.artifactId} + + + + + + diff --git a/zhi-admin/src/main/java/com/zhi/RuoYiApplication.java b/zhi-admin/src/main/java/com/zhi/RuoYiApplication.java new file mode 100644 index 0000000..6e17f47 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/RuoYiApplication.java @@ -0,0 +1,25 @@ +package com.zhi; + +import cn.easyes.starter.register.EsMapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; + +/** + * 启动程序 + * + * @author ruoyi + */ + +@SpringBootApplication +@EsMapperScan("com.zhi.blog.easyesMapper") +public class RuoYiApplication { + public static void main(String[] args) { + System.setProperty("spring.devtools.restart.enabled", "false"); + SpringApplication application = new SpringApplication(RuoYiApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ zhi-blog启动成功 ლ(´ڡ`ლ)゙"); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/RuoYiServletInitializer.java b/zhi-admin/src/main/java/com/zhi/RuoYiServletInitializer.java new file mode 100644 index 0000000..fad455f --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/RuoYiServletInitializer.java @@ -0,0 +1,18 @@ +package com.zhi; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author ruoyi + */ +public class RuoYiServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(RuoYiApplication.class); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/blogSearch/ArticleSearch.java b/zhi-admin/src/main/java/com/zhi/web/controller/blogSearch/ArticleSearch.java new file mode 100644 index 0000000..96e59f0 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/blogSearch/ArticleSearch.java @@ -0,0 +1,41 @@ +package com.zhi.web.controller.blogSearch; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.zhi.blog.dto.ArticleSearchDTO; +import com.zhi.blog.dto.vo.ConditionVO; +import com.zhi.common.core.domain.R; +import com.zhi.web.controller.strategy.context.SearchStrategyContext; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; + +/** + * @author ftz-lover + * @version 1.0 + * @date 2023/1/17 18:55 + */ + +@RestController +public class ArticleSearch { + + @Resource + private SearchStrategyContext searchStrategyContext; + + + /** + * 搜索文章 + * + * @param condition 条件 + * @return {@link R} 文章列表 + */ + @SaIgnore + @ApiOperation(value = "搜索文章") + @GetMapping("/articles/search") + public R> listArticlesBySearch(ConditionVO condition) { + return R.ok( searchStrategyContext.executeSearchStrategy(condition.getKeywords())); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/common/CaptchaController.java b/zhi-admin/src/main/java/com/zhi/web/controller/common/CaptchaController.java new file mode 100644 index 0000000..99c60b2 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/common/CaptchaController.java @@ -0,0 +1,122 @@ +package com.zhi.web.controller.common; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import com.zhi.common.constant.CacheConstants; +import com.zhi.common.constant.Constants; +import com.zhi.common.core.domain.R; +import com.zhi.common.enums.CaptchaType; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.redis.RedisUtils; +import com.zhi.common.utils.reflect.ReflectUtils; +import com.zhi.common.utils.spring.SpringUtils; +import com.zhi.framework.config.properties.CaptchaProperties; +import com.zhi.sms.config.properties.SmsProperties; +import com.zhi.sms.core.SmsTemplate; +import com.zhi.sms.entity.SmsResult; +import com.zhi.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.NotBlank; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; + +/** + * 验证码操作处理 + * + * @author Lion Li + */ +@SaIgnore +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +public class CaptchaController { + + private final CaptchaProperties captchaProperties; + private final SmsProperties smsProperties; + private final ISysConfigService configService; + + /** + * 短信验证码 + * + * @param phonenumber 用户手机号 + */ + @GetMapping("/captchaSms") + public R smsCaptcha(@NotBlank(message = "{user.phonenumber.not.blank}") + String phonenumber) { + if (!smsProperties.getEnabled()) { + return R.fail("当前系统没有开启短信功能!"); + } + String key = CacheConstants.CAPTCHA_CODE_KEY + phonenumber; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + // 验证码模板id 自行处理 (查数据库或写死均可) + String templateId = ""; + Map map = new HashMap<>(1); + map.put("code", code); + SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); + SmsResult result = smsTemplate.send(phonenumber, templateId, map); + if (!result.isSuccess()) { + log.error("验证码短信发送异常 => {}", result); + return R.fail(result.getMessage()); + } + return R.ok(); + } + + /** + * 生成验证码 + */ + @GetMapping("/captchaImage") + public R> getCode() { + Map ajax = new HashMap<>(); + boolean captchaEnabled = configService.selectCaptchaEnabled(); + ajax.put("captchaEnabled", captchaEnabled); + if (!captchaEnabled) { + return R.ok(ajax); + } + // 保存验证码信息 + String uuid = IdUtil.simpleUUID(); + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid; + // 生成验证码 + CaptchaType captchaType = captchaProperties.getType(); + boolean isMath = CaptchaType.MATH == captchaType; + Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); + CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); + AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); + captcha.setGenerator(codeGenerator); + captcha.createCode(); + String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode(); + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + ajax.put("uuid", uuid); + ajax.put("img", captcha.getImageBase64()); + return R.ok(ajax); + } + + private String getCodeResult(String capStr) { + int numberLength = captchaProperties.getNumberLength(); + int a = Convert.toInt(StringUtils.substring(capStr, 0, numberLength).trim()); + char operator = capStr.charAt(numberLength); + int b = Convert.toInt(StringUtils.substring(capStr, numberLength + 1, numberLength + 1 + numberLength).trim()); + switch (operator) { + case '*': + return Convert.toStr(a * b); + case '+': + return Convert.toStr(a + b); + case '-': + return Convert.toStr(a - b); + default: + return StringUtils.EMPTY; + } + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/consumer/EmailConsumer.java b/zhi-admin/src/main/java/com/zhi/web/controller/consumer/EmailConsumer.java new file mode 100644 index 0000000..37d729a --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/consumer/EmailConsumer.java @@ -0,0 +1,37 @@ +package com.zhi.web.controller.consumer; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.extra.mail.MailAccount; +import cn.hutool.extra.mail.MailUtil; +import com.alibaba.fastjson.JSON; +import com.zhi.common.utils.email.MailUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.rabbit.annotation.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import static com.zhi.common.constant.blog.MQPrefixConst.EMAIL_EXCHANGE; +import static com.zhi.common.constant.blog.MQPrefixConst.EMAIL_QUEUE; +import com.zhi.system.dto.EmailDTO; +/** + * 通知邮箱 + * + * @author water-zhi + * @date 2021/06/13 + * @since 1.0.0 + **/ +@Slf4j +@Component +@RabbitListener(bindings = @QueueBinding( + value = @Queue(EMAIL_QUEUE), + exchange = @Exchange(EMAIL_EXCHANGE) +)) +public class EmailConsumer { + + @RabbitHandler + public void process(byte[] data) { + + EmailDTO emailDTO = JSON.parseObject(new String(data), EmailDTO.class); + log.info(emailDTO.toString()); + MailUtils.sendText(emailDTO.getEmail(),emailDTO.getSubject(),emailDTO.getContent()); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/monitor/CacheController.java b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/CacheController.java new file mode 100644 index 0000000..e62a0da --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/CacheController.java @@ -0,0 +1,169 @@ +package com.zhi.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.collection.CollUtil; +import com.zhi.common.constant.CacheConstants; +import com.zhi.common.constant.CacheNames; +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.JsonUtils; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.redis.CacheUtils; +import com.zhi.common.utils.redis.RedisUtils; +import com.zhi.system.domain.SysCache; +import lombok.RequiredArgsConstructor; +import org.redisson.spring.data.connection.RedissonConnectionFactory; +import org.springframework.data.redis.connection.RedisConnection; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 缓存监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/cache") +public class CacheController { + + private final RedissonConnectionFactory connectionFactory; + + private final static List CACHES = new ArrayList<>(); + + static { + CACHES.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息")); + CACHES.add(new SysCache(CacheConstants.ONLINE_TOKEN_KEY, "在线用户")); + CACHES.add(new SysCache(CacheNames.SYS_CONFIG, "配置信息")); + CACHES.add(new SysCache(CacheNames.SYS_DICT, "数据字典")); + CACHES.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码")); + CACHES.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); + CACHES.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); + CACHES.add(new SysCache(CacheNames.SYS_OSS_CONFIG, "OSS配置")); + CACHES.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); + } + + /** + * 获取缓存监控列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping() + public R> getInfo() throws Exception { + RedisConnection connection = connectionFactory.getConnection(); + Properties info = connection.info(); + Properties commandStats = connection.info("commandstats"); + Long dbSize = connection.dbSize(); + + Map result = new HashMap<>(3); + result.put("info", info); + result.put("dbSize", dbSize); + + List> pieList = new ArrayList<>(); + if (commandStats != null) { + commandStats.stringPropertyNames().forEach(key -> { + Map data = new HashMap<>(2); + String property = commandStats.getProperty(key); + data.put("name", StringUtils.removeStart(key, "cmdstat_")); + data.put("value", StringUtils.substringBetween(property, "calls=", ",usec")); + pieList.add(data); + }); + } + result.put("commandStats", pieList); + return R.ok(result); + } + + /** + * 获取缓存监控缓存名列表 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping("/getNames") + public R> cache() { + return R.ok(CACHES); + } + + /** + * 获取缓存监控Key列表 + * + * @param cacheName 缓存名 + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping("/getKeys/{cacheName}") + public R> getCacheKeys(@PathVariable String cacheName) { + Collection cacheKeys = new HashSet<>(0); + if (isCacheNames(cacheName)) { + Set keys = CacheUtils.keys(cacheName); + if (CollUtil.isNotEmpty(keys)) { + cacheKeys = keys.stream().map(Object::toString).collect(Collectors.toList()); + } + } else { + cacheKeys = RedisUtils.keys(cacheName + "*"); + } + return R.ok(cacheKeys); + } + + /** + * 获取缓存监控缓存值详情 + * + * @param cacheName 缓存名 + * @param cacheKey 缓存key + */ + @SaCheckPermission("monitor:cache:list") + @GetMapping("/getValue/{cacheName}/{cacheKey}") + public R getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) { + Object cacheValue; + if (isCacheNames(cacheName)) { + cacheValue = CacheUtils.get(cacheName, cacheKey); + } else { + cacheValue = RedisUtils.getCacheObject(cacheKey); + } + SysCache sysCache = new SysCache(cacheName, cacheKey, JsonUtils.toJsonString(cacheValue)); + return R.ok(sysCache); + } + + /** + * 清理缓存监控缓存名 + * + * @param cacheName 缓存名 + */ + @SaCheckPermission("monitor:cache:list") + @DeleteMapping("/clearCacheName/{cacheName}") + public R clearCacheName(@PathVariable String cacheName) { + if (isCacheNames(cacheName)) { + CacheUtils.clear(cacheName); + } else { + RedisUtils.deleteKeys(cacheName + "*"); + } + return R.ok(); + } + + /** + * 清理缓存监控Key + * + * @param cacheKey key名 + */ + @SaCheckPermission("monitor:cache:list") + @DeleteMapping("/clearCacheKey/{cacheName}/{cacheKey}") + public R clearCacheKey(@PathVariable String cacheName, @PathVariable String cacheKey) { + if (isCacheNames(cacheName)) { + CacheUtils.evict(cacheName, cacheKey); + } else { + RedisUtils.deleteObject(cacheKey); + } + return R.ok(); + } + + /** + * 清理全部缓存监控 + */ + @SaCheckPermission("monitor:cache:list") + @DeleteMapping("/clearCacheAll") + public R clearCacheAll() { + RedisUtils.deleteKeys("*"); + return R.ok(); + } + + private boolean isCacheNames(String cacheName) { + return !StringUtils.contains(cacheName, ":"); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysLogininforController.java b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysLogininforController.java new file mode 100644 index 0000000..87259c7 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysLogininforController.java @@ -0,0 +1,88 @@ +package com.zhi.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.CacheConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.common.utils.redis.RedisUtils; +import com.zhi.system.domain.SysLogininfor; +import com.zhi.system.service.ISysLogininforService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 系统访问记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/logininfor") +public class SysLogininforController extends BaseController { + + private final ISysLogininforService logininforService; + + /** + * 获取系统访问记录列表 + */ + @SaCheckPermission("monitor:logininfor:list") + @GetMapping("/list") + public TableDataInfo list(SysLogininfor logininfor, PageQuery pageQuery) { + return logininforService.selectPageLogininforList(logininfor, pageQuery); + } + + /** + * 导出系统访问记录列表 + */ + @Log(title = "登录日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:logininfor:export") + @PostMapping("/export") + public void export(SysLogininfor logininfor, HttpServletResponse response) { + List list = logininforService.selectLogininforList(logininfor); + ExcelUtil.exportExcel(list, "登录日志", SysLogininfor.class, response); + } + + /** + * 批量删除登录日志 + * @param infoIds 日志ids + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.DELETE) + @DeleteMapping("/{infoIds}") + public R remove(@PathVariable Long[] infoIds) { + return toAjax(logininforService.deleteLogininforByIds(infoIds)); + } + + /** + * 清理系统访问记录 + */ + @SaCheckPermission("monitor:logininfor:remove") + @Log(title = "登录日志", businessType = BusinessType.CLEAN) + @DeleteMapping("/clean") + public R clean() { + logininforService.cleanLogininfor(); + return R.ok(); + } + + @SaCheckPermission("monitor:logininfor:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @GetMapping("/unlock/{userName}") + public R unlock(@PathVariable("userName") String userName) { + String loginName = CacheConstants.PWD_ERR_CNT_KEY + userName; + if (RedisUtils.hasKey(loginName)) { + RedisUtils.deleteObject(loginName); + } + return R.ok(); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysOperlogController.java b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysOperlogController.java new file mode 100644 index 0000000..efcef13 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysOperlogController.java @@ -0,0 +1,74 @@ +package com.zhi.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.domain.SysOperLog; +import com.zhi.system.service.ISysOperLogService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 操作日志记录 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/operlog") +public class SysOperlogController extends BaseController { + + private final ISysOperLogService operLogService; + + /** + * 获取操作日志记录列表 + */ + @SaCheckPermission("monitor:operlog:list") + @GetMapping("/list") + public TableDataInfo list(SysOperLog operLog, PageQuery pageQuery) { + return operLogService.selectPageOperLogList(operLog, pageQuery); + } + + /** + * 导出操作日志记录列表 + */ + @Log(title = "操作日志", businessType = BusinessType.EXPORT) + @SaCheckPermission("monitor:operlog:export") + @PostMapping("/export") + public void export(SysOperLog operLog, HttpServletResponse response) { + List list = operLogService.selectOperLogList(operLog); + ExcelUtil.exportExcel(list, "操作日志", SysOperLog.class, response); + } + + /** + * 批量删除操作日志记录 + * @param operIds 日志ids + */ + @Log(title = "操作日志", businessType = BusinessType.DELETE) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/{operIds}") + public R remove(@PathVariable Long[] operIds) { + return toAjax(operLogService.deleteOperLogByIds(operIds)); + } + + /** + * 清理操作日志记录 + */ + @Log(title = "操作日志", businessType = BusinessType.CLEAN) + @SaCheckPermission("monitor:operlog:remove") + @DeleteMapping("/clean") + public R clean() { + operLogService.cleanOperLog(); + return R.ok(); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysUserOnlineController.java b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysUserOnlineController.java new file mode 100644 index 0000000..04d1bc3 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/monitor/SysUserOnlineController.java @@ -0,0 +1,90 @@ +package com.zhi.web.controller.monitor; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.CacheConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.dto.UserOnlineDTO; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.StreamUtils; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.redis.RedisUtils; +import com.zhi.system.domain.SysUserOnline; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 在线用户监控 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/monitor/online") +public class SysUserOnlineController extends BaseController { + + /** + * 获取在线用户监控列表 + * + * @param ipaddr IP地址 + * @param userName 用户名 + */ + @SaCheckPermission("monitor:online:list") + @GetMapping("/list") + public TableDataInfo list(String ipaddr, String userName) { + // 获取所有未过期的 token + List keys = StpUtil.searchTokenValue("", 0, -1, false); + List userOnlineDTOList = new ArrayList<>(); + for (String key : keys) { + String token = key.replace(CacheConstants.LOGIN_TOKEN_KEY, ""); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) { + continue; + } + userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)); + } + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + Collections.reverse(userOnlineDTOList); + userOnlineDTOList.removeAll(Collections.singleton(null)); + List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); + return TableDataInfo.build(userOnlineList); + } + + /** + * 强退用户 + * + * @param tokenId token值 + */ + @SaCheckPermission("monitor:online:forceLogout") + @Log(title = "在线用户", businessType = BusinessType.FORCE) + @DeleteMapping("/{tokenId}") + public R forceLogout(@PathVariable String tokenId) { + try { + StpUtil.kickoutByTokenValue(tokenId); + } catch (NotLoginException ignored) { + } + return R.ok(); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/strategy/SearchStrategy.java b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/SearchStrategy.java new file mode 100644 index 0000000..1266065 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/SearchStrategy.java @@ -0,0 +1,21 @@ +package com.zhi.web.controller.strategy; +import com.zhi.blog.dto.ArticleSearchDTO; +import java.util.List; + +/** + * 搜索策略 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +public interface SearchStrategy { + + /** + * 搜索文章 + * + * @param keywords 关键字 + * @return {@link List} 文章列表 + */ + List searchArticle(String keywords); + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/strategy/context/SearchStrategyContext.java b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/context/SearchStrategyContext.java new file mode 100644 index 0000000..07b3301 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/context/SearchStrategyContext.java @@ -0,0 +1,41 @@ +package com.zhi.web.controller.strategy.context; + +import com.zhi.blog.dto.ArticleSearchDTO; +import com.zhi.web.controller.strategy.SearchStrategy; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static com.zhi.common.enums.blog.SearchModeEnum.getStrategy; + +/** + * 搜索策略上下文 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +@Service +public class SearchStrategyContext { + /** + * 搜索模式 + */ + @Value("${search.mode}") + private String searchMode; + + @Resource + private Map searchStrategyMap; + + /** + * 执行搜索策略 + * + * @param keywords 关键字 + * @return {@link List} 搜索文章 + */ + public List executeSearchStrategy(String keywords) { + return searchStrategyMap.get(getStrategy(searchMode)).searchArticle(keywords); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/strategy/impl/EsSearchStrategyImpl.java b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/impl/EsSearchStrategyImpl.java new file mode 100644 index 0000000..1016ed9 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/impl/EsSearchStrategyImpl.java @@ -0,0 +1,80 @@ +//package com.zhi.web.controller.strategy.impl; +//import cn.easyes.core.conditions.LambdaEsQueryWrapper; +//import com.baomidou.mybatisplus.core.toolkit.StringUtils; +//import com.zhi.blog.domain.es.EsArticle; +//import com.zhi.blog.dto.ArticleSearchDTO; +//import com.zhi.blog.easyesMapper.EsArticleMapper; +//import com.zhi.web.controller.strategy.SearchStrategy; +//import lombok.extern.log4j.Log4j2; +//import org.springframework.stereotype.Service; +// +//import javax.annotation.Resource; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.stream.Collectors; +//import static com.zhi.common.constant.blog.CommonConst.*; +// +///** +// * es搜索策略实现 +// * +// * @author yezhiqiu +// * @date 2021/07/27 +// */ +//@Log4j2 +//@Service("esSearchStrategyImpl") +//public class EsSearchStrategyImpl implements SearchStrategy { +// +// +// @Resource +// private EsArticleMapper esArticleMapper; +// +// +// @Override +// public List searchArticle(String keywords) { +// if (StringUtils.isBlank(keywords)) { +// return new ArrayList<>(); +// } +// // 搜索文章 +// LambdaEsQueryWrapper wrapper = new LambdaEsQueryWrapper<>(); +// wrapper +// .eq(EsArticle::getStatus,ISTRUE) +// .eq(EsArticle::getType,ISTRUE) +// .and(i -> i +// .like(EsArticle::getArticle_title, keywords) +// .or() +// .like(EsArticle::getArticle_content, keywords) +// ); +// +// +// List articleList = esArticleMapper.selectList(wrapper); +// +// +// // 高亮处理 +// return articleList.stream().map(item -> { +// // 获取关键词第一次出现的位置 +// String articleContent = item.getArticle_content(); +// int index = item.getArticle_content().indexOf(keywords); +// if (index != -1) { +// // 获取关键词前面的文字 +// int preIndex = index > 25 ? index - 25 : 0; +// String preText = item.getArticle_content().substring(preIndex, index); +// // 获取关键词到后面的文字 +// int last = index + keywords.length(); +// int postLength = item.getArticle_content().length() - last; +// int postIndex = postLength > 175 ? last + 175 : last + postLength; +// String postText = item.getArticle_content().substring(index, postIndex); +// // 文章内容高亮 +// articleContent = (preText + postText).replaceAll(keywords, PRE_TAG + keywords + POST_TAG); +// } +// // 文章标题高亮 +// String articleTitle = item.getArticle_title().replaceAll(keywords, PRE_TAG + keywords + POST_TAG); +// return ArticleSearchDTO.builder() +// .id(item.getId()) +// .articleTitle(articleTitle) +// .articleContent(articleContent) +// .build(); +// }).collect(Collectors.toList()); +// +// } +// +//} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/strategy/impl/MySqlSearchStrategyImpl.java b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/impl/MySqlSearchStrategyImpl.java new file mode 100644 index 0000000..12082d7 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/strategy/impl/MySqlSearchStrategyImpl.java @@ -0,0 +1,71 @@ +package com.zhi.web.controller.strategy.impl; + + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.zhi.blog.domain.Article; +import com.zhi.blog.dto.ArticleSearchDTO; +import com.zhi.blog.mapper.ArticleMapper; +import com.zhi.web.controller.strategy.SearchStrategy; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import static com.zhi.common.constant.blog.CommonConst.*; +import static com.zhi.common.enums.blog.ArticleStatusEnum.PUBLIC; + +/** + * mysql搜索策略 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +@Service("mySqlSearchStrategyImpl") +public class MySqlSearchStrategyImpl implements SearchStrategy { + @Resource + private ArticleMapper articleMapper; + + @Override + public List searchArticle(String keywords) { + // 判空 + if (StringUtils.isBlank(keywords)) { + return new ArrayList<>(); + } + // 搜索文章 + List
articleList = articleMapper.selectList(new LambdaQueryWrapper
() + .eq(Article::getIsDelete, FALSE) + .eq(Article::getStatus, PUBLIC.getStatus()) + .and(i -> i.like(Article::getArticleTitle, keywords) + .or() + .like(Article::getArticleContent, keywords))); + // 高亮处理 + return articleList.stream().map(item -> { + // 获取关键词第一次出现的位置 + String articleContent = item.getArticleContent(); + int index = item.getArticleContent().indexOf(keywords); + if (index != -1) { + // 获取关键词前面的文字 + int preIndex = index > 25 ? index - 25 : 0; + String preText = item.getArticleContent().substring(preIndex, index); + // 获取关键词到后面的文字 + int last = index + keywords.length(); + int postLength = item.getArticleContent().length() - last; + int postIndex = postLength > 175 ? last + 175 : last + postLength; + String postText = item.getArticleContent().substring(index, postIndex); + // 文章内容高亮 + articleContent = (preText + postText).replaceAll(keywords, PRE_TAG + keywords + POST_TAG); + } + // 文章标题高亮 + String articleTitle = item.getArticleTitle().replaceAll(keywords, PRE_TAG + keywords + POST_TAG); + return ArticleSearchDTO.builder() + .id(item.getId()) + .articleTitle(articleTitle) + .articleContent(articleContent) + .build(); + }).collect(Collectors.toList()); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysConfigController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysConfigController.java new file mode 100644 index 0000000..7b1404b --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysConfigController.java @@ -0,0 +1,137 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.domain.SysConfig; +import com.zhi.system.service.ISysConfigService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 参数配置 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/config") +public class SysConfigController extends BaseController { + + private final ISysConfigService configService; + + /** + * 获取参数配置列表 + */ + @SaCheckPermission("system:config:list") + @GetMapping("/list") + public TableDataInfo list(SysConfig config, PageQuery pageQuery) { + return configService.selectPageConfigList(config, pageQuery); + } + + /** + * 导出参数配置列表 + */ + @Log(title = "参数管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:config:export") + @PostMapping("/export") + public void export(SysConfig config, HttpServletResponse response) { + List list = configService.selectConfigList(config); + ExcelUtil.exportExcel(list, "参数数据", SysConfig.class, response); + } + + /** + * 根据参数编号获取详细信息 + * + * @param configId 参数ID + */ + @SaCheckPermission("system:config:query") + @GetMapping(value = "/{configId}") + public R getInfo(@PathVariable Long configId) { + return R.ok(configService.selectConfigById(configId)); + } + + /** + * 根据参数键名查询参数值 + * + * @param configKey 参数Key + */ + @GetMapping(value = "/configKey/{configKey}") + public R getConfigKey(@PathVariable String configKey) { + return R.ok(configService.selectConfigByKey(configKey)); + } + + /** + * 新增参数配置 + */ + @SaCheckPermission("system:config:add") + @Log(title = "参数管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysConfig config) { + if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) { + return R.fail("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.insertConfig(config); + return R.ok(); + } + + /** + * 修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysConfig config) { + if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) { + return R.fail("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); + } + configService.updateConfig(config); + return R.ok(); + } + + /** + * 根据参数键名修改参数配置 + */ + @SaCheckPermission("system:config:edit") + @Log(title = "参数管理", businessType = BusinessType.UPDATE) + @PutMapping("/updateByKey") + public R updateByKey(@RequestBody SysConfig config) { + configService.updateConfig(config); + return R.ok(); + } + + /** + * 删除参数配置 + * + * @param configIds 参数ID串 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{configIds}") + public R remove(@PathVariable Long[] configIds) { + configService.deleteConfigByIds(configIds); + return R.ok(); + } + + /** + * 刷新参数缓存 + */ + @SaCheckPermission("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + configService.resetConfigCache(); + return R.ok(); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDeptController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDeptController.java new file mode 100644 index 0000000..911d578 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDeptController.java @@ -0,0 +1,119 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ArrayUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysDept; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.StringUtils; +import com.zhi.system.service.ISysDeptService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 部门信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dept") +public class SysDeptController extends BaseController { + + private final ISysDeptService deptService; + + /** + * 获取部门列表 + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list") + public R> list(SysDept dept) { + List depts = deptService.selectDeptList(dept); + return R.ok(depts); + } + + /** + * 查询部门列表(排除节点) + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:list") + @GetMapping("/list/exclude/{deptId}") + public R> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) { + List depts = deptService.selectDeptList(new SysDept()); + depts.removeIf(d -> d.getDeptId().equals(deptId) + || ArrayUtil.contains(StringUtils.split(d.getAncestors(), ","), deptId + "")); + return R.ok(depts); + } + + /** + * 根据部门编号获取详细信息 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:query") + @GetMapping(value = "/{deptId}") + public R getInfo(@PathVariable Long deptId) { + deptService.checkDeptDataScope(deptId); + return R.ok(deptService.selectDeptById(deptId)); + } + + /** + * 新增部门 + */ + @SaCheckPermission("system:dept:add") + @Log(title = "部门管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDept dept) { + if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) { + return R.fail("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } + return toAjax(deptService.insertDept(dept)); + } + + /** + * 修改部门 + */ + @SaCheckPermission("system:dept:edit") + @Log(title = "部门管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDept dept) { + Long deptId = dept.getDeptId(); + deptService.checkDeptDataScope(deptId); + if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); + } else if (dept.getParentId().equals(deptId)) { + return R.fail("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); + } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) + && deptService.selectNormalChildrenDeptById(deptId) > 0) { + return R.fail("该部门包含未停用的子部门!"); + } + return toAjax(deptService.updateDept(dept)); + } + + /** + * 删除部门 + * + * @param deptId 部门ID + */ + @SaCheckPermission("system:dept:remove") + @Log(title = "部门管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{deptId}") + public R remove(@PathVariable Long deptId) { + if (deptService.hasChildByDeptId(deptId)) { + return R.warn("存在下级部门,不允许删除"); + } + if (deptService.checkDeptExistUser(deptId)) { + return R.warn("部门存在用户,不允许删除"); + } + deptService.checkDeptDataScope(deptId); + return toAjax(deptService.deleteDeptById(deptId)); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDictDataController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDictDataController.java new file mode 100644 index 0000000..84d2e8b --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDictDataController.java @@ -0,0 +1,116 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysDictData; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.service.ISysDictDataService; +import com.zhi.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/data") +public class SysDictDataController extends BaseController { + + private final ISysDictDataService dictDataService; + private final ISysDictTypeService dictTypeService; + + /** + * 查询字典数据列表 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictData dictData, PageQuery pageQuery) { + return dictDataService.selectPageDictDataList(dictData, pageQuery); + } + + /** + * 导出字典数据列表 + */ + @Log(title = "字典数据", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictData dictData, HttpServletResponse response) { + List list = dictDataService.selectDictDataList(dictData); + ExcelUtil.exportExcel(list, "字典数据", SysDictData.class, response); + } + + /** + * 查询字典数据详细 + * + * @param dictCode 字典code + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictCode}") + public R getInfo(@PathVariable Long dictCode) { + return R.ok(dictDataService.selectDictDataById(dictCode)); + } + + /** + * 根据字典类型查询字典数据信息 + * + * @param dictType 字典类型 + */ + @GetMapping(value = "/type/{dictType}") + public R> dictType(@PathVariable String dictType) { + List data = dictTypeService.selectDictDataByType(dictType); + if (ObjectUtil.isNull(data)) { + data = new ArrayList<>(); + } + return R.ok(data); + } + + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典数据", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictData dict) { + dictDataService.insertDictData(dict); + return R.ok(); + } + + /** + * 修改保存字典类型 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典数据", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictData dict) { + dictDataService.updateDictData(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictCodes 字典code串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictCodes}") + public R remove(@PathVariable Long[] dictCodes) { + dictDataService.deleteDictDataByIds(dictCodes); + return R.ok(); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDictTypeController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDictTypeController.java new file mode 100644 index 0000000..7c9b5bc --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysDictTypeController.java @@ -0,0 +1,125 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysDictType; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.service.ISysDictTypeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 数据字典信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/dict/type") +public class SysDictTypeController extends BaseController { + + private final ISysDictTypeService dictTypeService; + + /** + * 查询字典类型列表 + */ + @SaCheckPermission("system:dict:list") + @GetMapping("/list") + public TableDataInfo list(SysDictType dictType, PageQuery pageQuery) { + return dictTypeService.selectPageDictTypeList(dictType, pageQuery); + } + + /** + * 导出字典类型列表 + */ + @Log(title = "字典类型", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:dict:export") + @PostMapping("/export") + public void export(SysDictType dictType, HttpServletResponse response) { + List list = dictTypeService.selectDictTypeList(dictType); + ExcelUtil.exportExcel(list, "字典类型", SysDictType.class, response); + } + + /** + * 查询字典类型详细 + * + * @param dictId 字典ID + */ + @SaCheckPermission("system:dict:query") + @GetMapping(value = "/{dictId}") + public R getInfo(@PathVariable Long dictId) { + return R.ok(dictTypeService.selectDictTypeById(dictId)); + } + + /** + * 新增字典类型 + */ + @SaCheckPermission("system:dict:add") + @Log(title = "字典类型", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysDictType dict) { + if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) { + return R.fail("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.insertDictType(dict); + return R.ok(); + } + + /** + * 修改字典类型 + */ + @SaCheckPermission("system:dict:edit") + @Log(title = "字典类型", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysDictType dict) { + if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) { + return R.fail("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); + } + dictTypeService.updateDictType(dict); + return R.ok(); + } + + /** + * 删除字典类型 + * + * @param dictIds 字典ID串 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.DELETE) + @DeleteMapping("/{dictIds}") + public R remove(@PathVariable Long[] dictIds) { + dictTypeService.deleteDictTypeByIds(dictIds); + return R.ok(); + } + + /** + * 刷新字典缓存 + */ + @SaCheckPermission("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @DeleteMapping("/refreshCache") + public R refreshCache() { + dictTypeService.resetDictCache(); + return R.ok(); + } + + /** + * 获取字典选择框列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List dictTypes = dictTypeService.selectDictTypeAll(); + return R.ok(dictTypes); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysIndexController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysIndexController.java new file mode 100644 index 0000000..11187e6 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysIndexController.java @@ -0,0 +1,32 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.zhi.common.config.RuoYiConfig; +import com.zhi.common.utils.StringUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 首页 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +public class SysIndexController { + + /** + * 系统基础配置 + */ + private final RuoYiConfig ruoyiConfig; + + /** + * 访问首页,提示语 + */ + @SaIgnore + @GetMapping("/") + public String index() { + return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion()); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysLoginController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysLoginController.java new file mode 100644 index 0000000..5b07b08 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysLoginController.java @@ -0,0 +1,162 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.zhi.common.constant.Constants; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysMenu; +import com.zhi.common.core.domain.entity.SysUser; +import com.zhi.common.core.domain.model.LoginBody; +import com.zhi.common.core.domain.model.LoginUser; +import com.zhi.common.core.domain.model.SmsLoginBody; +import com.zhi.common.helper.LoginHelper; +import com.zhi.system.domain.vo.RouterVo; +import com.zhi.system.service.ISysMenuService; +import com.zhi.system.service.ISysUserService; +import com.zhi.system.service.SysLoginService; +import com.zhi.system.service.SysPermissionService; +import lombok.RequiredArgsConstructor; +import org.apache.ibatis.annotations.Param; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.constraints.NotBlank; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 登录验证 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +public class SysLoginController { + + private final SysLoginService loginService; + private final ISysMenuService menuService; + private final ISysUserService userService; + + private final SysPermissionService permissionService; + + + + + + + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @SaIgnore + @PostMapping("/login") + public R> login(@Validated @RequestBody LoginBody loginBody) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + loginBody.getUuid()); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + + /** + * 前台博客登录 + */ + @SaIgnore + @PostMapping("/blog/login") + public R blogLogin(String username,String password){ + return R.ok(loginService.bloglogin(username,password)); + } + + /** + * 根据用户id返回用户信息 + */ + @SaIgnore + @PostMapping("/oauth/login") + public R oauthLogin(String userid){ + return R.ok( loginService.getLoginUserById(Long.valueOf(userid))); + } + + /** + * 短信登录(示例) + * + * @param smsLoginBody 登录信息 + * @return 结果 + */ + @SaIgnore + @PostMapping("/smsLogin") + public R> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode()); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + + /** + * 小程序登录(示例) + * + * @param xcxCode 小程序code + * @return 结果 + */ + @SaIgnore + @PostMapping("/xcxLogin") + public R> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { + Map ajax = new HashMap<>(); + // 生成令牌 + String token = loginService.xcxLogin(xcxCode); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + + /** + * 退出登录 + */ + @SaIgnore + @PostMapping("/logout") + public R logout() { + loginService.logout(); + return R.ok("退出成功"); + } + + /** + * 博客前台退出登录 + */ + @SaIgnore + @GetMapping("/blogLogout") + public R blogLogout(){ + return R.ok("推出成功"); + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("getInfo") + public R> getInfo() { + LoginUser loginUser = LoginHelper.getLoginUser(); + SysUser user = userService.selectUserById(loginUser.getUserId()); + Map ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roles", loginUser.getRolePermission()); + ajax.put("permissions", loginUser.getMenuPermission()); + return R.ok(ajax); + } + + /** + * 获取路由信息 + * + * @return 路由信息 + */ + @GetMapping("getRouters") + public R> getRouters() { + Long userId = LoginHelper.getUserId(); + List menus = menuService.selectMenuTreeByUserId(userId); + return R.ok(menuService.buildMenus(menus)); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysMenuController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysMenuController.java new file mode 100644 index 0000000..924e4da --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysMenuController.java @@ -0,0 +1,127 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.lang.tree.Tree; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysMenu; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.StringUtils; +import com.zhi.system.service.ISysMenuService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 菜单信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/menu") +public class SysMenuController extends BaseController { + + private final ISysMenuService menuService; + + /** + * 获取菜单列表 + */ + @SaCheckPermission("system:menu:list") + @GetMapping("/list") + public R> list(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return R.ok(menus); + } + + /** + * 根据菜单编号获取详细信息 + * + * @param menuId 菜单ID + */ + @SaCheckPermission("system:menu:query") + @GetMapping(value = "/{menuId}") + public R getInfo(@PathVariable Long menuId) { + return R.ok(menuService.selectMenuById(menuId)); + } + + /** + * 获取菜单下拉树列表 + */ + @GetMapping("/treeselect") + public R>> treeselect(SysMenu menu) { + List menus = menuService.selectMenuList(menu, getUserId()); + return R.ok(menuService.buildMenuTreeSelect(menus)); + } + + /** + * 加载对应角色菜单列表树 + * + * @param roleId 角色ID + */ + @GetMapping(value = "/roleMenuTreeselect/{roleId}") + public R> roleMenuTreeselect(@PathVariable("roleId") Long roleId) { + List menus = menuService.selectMenuList(getUserId()); + Map ajax = new HashMap<>(); + ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId)); + ajax.put("menus", menuService.buildMenuTreeSelect(menus)); + return R.ok(ajax); + } + + /** + * 新增菜单 + */ + @SaCheckPermission("system:menu:add") + @Log(title = "菜单管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysMenu menu) { + if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } + return toAjax(menuService.insertMenu(menu)); + } + + /** + * 修改菜单 + */ + @SaCheckPermission("system:menu:edit") + @Log(title = "菜单管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysMenu menu) { + if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); + } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头"); + } else if (menu.getMenuId().equals(menu.getParentId())) { + return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己"); + } + return toAjax(menuService.updateMenu(menu)); + } + + /** + * 删除菜单 + * + * @param menuId 菜单ID + */ + @SaCheckPermission("system:menu:remove") + @Log(title = "菜单管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{menuId}") + public R remove(@PathVariable("menuId") Long menuId) { + if (menuService.hasChildByMenuId(menuId)) { + return R.warn("存在子菜单,不允许删除"); + } + if (menuService.checkMenuExistRole(menuId)) { + return R.warn("菜单已分配,不允许删除"); + } + return toAjax(menuService.deleteMenuById(menuId)); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysNoticeController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysNoticeController.java new file mode 100644 index 0000000..32abcc2 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysNoticeController.java @@ -0,0 +1,80 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.system.domain.SysNotice; +import com.zhi.system.service.ISysNoticeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +/** + * 公告 信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/notice") +public class SysNoticeController extends BaseController { + + private final ISysNoticeService noticeService; + + /** + * 获取通知公告列表 + */ + @SaCheckPermission("system:notice:list") + @GetMapping("/list") + public TableDataInfo list(SysNotice notice, PageQuery pageQuery) { + return noticeService.selectPageNoticeList(notice, pageQuery); + } + + /** + * 根据通知公告编号获取详细信息 + * + * @param noticeId 公告ID + */ + @SaCheckPermission("system:notice:query") + @GetMapping(value = "/{noticeId}") + public R getInfo(@PathVariable Long noticeId) { + return R.ok(noticeService.selectNoticeById(noticeId)); + } + + /** + * 新增通知公告 + */ + @SaCheckPermission("system:notice:add") + @Log(title = "通知公告", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysNotice notice) { + return toAjax(noticeService.insertNotice(notice)); + } + + /** + * 修改通知公告 + */ + @SaCheckPermission("system:notice:edit") + @Log(title = "通知公告", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysNotice notice) { + return toAjax(noticeService.updateNotice(notice)); + } + + /** + * 删除通知公告 + * + * @param noticeIds 公告ID串 + */ + @SaCheckPermission("system:notice:remove") + @Log(title = "通知公告", businessType = BusinessType.DELETE) + @DeleteMapping("/{noticeIds}") + public R remove(@PathVariable Long[] noticeIds) { + return toAjax(noticeService.deleteNoticeByIds(noticeIds)); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysOssConfigController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysOssConfigController.java new file mode 100644 index 0000000..0e8c585 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysOssConfigController.java @@ -0,0 +1,105 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.annotation.RepeatSubmit; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.core.validate.AddGroup; +import com.zhi.common.core.validate.EditGroup; +import com.zhi.common.core.validate.QueryGroup; +import com.zhi.common.enums.BusinessType; +import com.zhi.system.domain.bo.SysOssConfigBo; +import com.zhi.system.domain.vo.SysOssConfigVo; +import com.zhi.system.service.ISysOssConfigService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; + +/** + * 对象存储配置 + * + * @author Lion Li + * @author 孤舟烟雨 + * @date 2021-08-13 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/oss/config") +public class SysOssConfigController extends BaseController { + + private final ISysOssConfigService iSysOssConfigService; + + /** + * 查询对象存储配置列表 + */ + @SaCheckPermission("system:oss:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) { + return iSysOssConfigService.queryPageList(bo, pageQuery); + } + + /** + * 获取对象存储配置详细信息 + * + * @param ossConfigId OSS配置ID + */ + @SaCheckPermission("system:oss:query") + @GetMapping("/{ossConfigId}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long ossConfigId) { + return R.ok(iSysOssConfigService.queryById(ossConfigId)); + } + + /** + * 新增对象存储配置 + */ + @SaCheckPermission("system:oss:add") + @Log(title = "对象存储配置", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(iSysOssConfigService.insertByBo(bo)); + } + + /** + * 修改对象存储配置 + */ + @SaCheckPermission("system:oss:edit") + @Log(title = "对象存储配置", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) { + return toAjax(iSysOssConfigService.updateByBo(bo)); + } + + /** + * 删除对象存储配置 + * + * @param ossConfigIds OSS配置ID串 + */ + @SaCheckPermission("system:oss:remove") + @Log(title = "对象存储配置", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossConfigIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossConfigIds) { + return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:oss:edit") + @Log(title = "对象存储状态修改", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysOssConfigBo bo) { + return toAjax(iSysOssConfigService.updateOssConfigStatus(bo)); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysOssController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysOssController.java new file mode 100644 index 0000000..512969c --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysOssController.java @@ -0,0 +1,110 @@ +package com.zhi.web.controller.system; + + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.core.validate.QueryGroup; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.exception.ServiceException; +import com.zhi.system.domain.bo.SysOssBo; +import com.zhi.system.domain.vo.SysOssVo; +import com.zhi.system.service.ISysOssService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 文件上传 控制层 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/oss") +public class SysOssController extends BaseController { + + private final ISysOssService iSysOssService; + + /** + * 查询OSS对象存储列表 + */ + @SaCheckPermission("system:oss:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) { + return iSysOssService.queryPageList(bo, pageQuery); + } + + /** + * 查询OSS对象基于id串 + * + * @param ossIds OSS对象ID串 + */ + @SaCheckPermission("system:oss:list") + @GetMapping("/listByIds/{ossIds}") + public R> listByIds(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + List list = iSysOssService.listByIds(Arrays.asList(ossIds)); + return R.ok(list); + } + + /** + * 上传OSS对象存储 + * + * @param file 文件 + */ + @SaCheckPermission("system:oss:upload") + @Log(title = "OSS对象存储", businessType = BusinessType.INSERT) + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R> upload(@RequestPart("file") MultipartFile file) { + if (ObjectUtil.isNull(file)) { + throw new ServiceException("上传文件不能为空"); + } + SysOssVo oss = iSysOssService.upload(file); + Map map = new HashMap<>(2); + map.put("url", oss.getUrl()); + map.put("fileName", oss.getOriginalName()); + map.put("ossId", oss.getOssId().toString()); + return R.ok(map); + } + + /** + * 下载OSS对象 + * + * @param ossId OSS对象ID + */ + @SaCheckPermission("system:oss:download") + @GetMapping("/download/{ossId}") + public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException { + iSysOssService.download(ossId,response); + } + + /** + * 删除OSS对象存储 + * + * @param ossIds OSS对象ID串 + */ + @SaCheckPermission("system:oss:remove") + @Log(title = "OSS对象存储", businessType = BusinessType.DELETE) + @DeleteMapping("/{ossIds}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ossIds) { + return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true)); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysPostController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysPostController.java new file mode 100644 index 0000000..9506581 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysPostController.java @@ -0,0 +1,115 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.domain.SysPost; +import com.zhi.system.service.ISysPostService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/post") +public class SysPostController extends BaseController { + + private final ISysPostService postService; + + /** + * 获取岗位列表 + */ + @SaCheckPermission("system:post:list") + @GetMapping("/list") + public TableDataInfo list(SysPost post, PageQuery pageQuery) { + return postService.selectPagePostList(post, pageQuery); + } + + /** + * 导出岗位列表 + */ + @Log(title = "岗位管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:post:export") + @PostMapping("/export") + public void export(SysPost post, HttpServletResponse response) { + List list = postService.selectPostList(post); + ExcelUtil.exportExcel(list, "岗位数据", SysPost.class, response); + } + + /** + * 根据岗位编号获取详细信息 + * + * @param postId 岗位ID + */ + @SaCheckPermission("system:post:query") + @GetMapping(value = "/{postId}") + public R getInfo(@PathVariable Long postId) { + return R.ok(postService.selectPostById(postId)); + } + + /** + * 新增岗位 + */ + @SaCheckPermission("system:post:add") + @Log(title = "岗位管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysPost post) { + if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) { + return R.fail("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.insertPost(post)); + } + + /** + * 修改岗位 + */ + @SaCheckPermission("system:post:edit") + @Log(title = "岗位管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysPost post) { + if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在"); + } else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) { + return R.fail("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在"); + } + return toAjax(postService.updatePost(post)); + } + + /** + * 删除岗位 + * + * @param postIds 岗位ID串 + */ + @SaCheckPermission("system:post:remove") + @Log(title = "岗位管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{postIds}") + public R remove(@PathVariable Long[] postIds) { + return toAjax(postService.deletePostByIds(postIds)); + } + + /** + * 获取岗位选择框列表 + */ + @GetMapping("/optionselect") + public R> optionselect() { + List posts = postService.selectPostAll(); + return R.ok(posts); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysProfileController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysProfileController.java new file mode 100644 index 0000000..e23abdc --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysProfileController.java @@ -0,0 +1,127 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.io.FileUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysUser; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.helper.LoginHelper; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.file.MimeTypeUtils; +import com.zhi.system.domain.vo.SysOssVo; +import com.zhi.system.service.ISysOssService; +import com.zhi.system.service.ISysUserService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * 个人信息 业务处理 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user/profile") +public class SysProfileController extends BaseController { + + private final ISysUserService userService; + private final ISysOssService iSysOssService; + + /** + * 个人信息 + */ + @GetMapping + public R> profile() { + SysUser user = userService.selectUserById(getUserId()); + Map ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roleGroup", userService.selectUserRoleGroup(user.getUserName())); + ajax.put("postGroup", userService.selectUserPostGroup(user.getUserName())); + return R.ok(ajax); + } + + /** + * 修改用户 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping + public R updateProfile(@RequestBody SysUser user) { + if (StringUtils.isNotEmpty(user.getPhonenumber()) + && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } + if (StringUtils.isNotEmpty(user.getEmail()) + && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setUserId(getUserId()); + user.setUserName(null); + user.setPassword(null); + user.setAvatar(null); + user.setDeptId(null); + if (userService.updateUserProfile(user) > 0) { + return R.ok(); + } + return R.fail("修改个人信息异常,请联系管理员"); + } + + /** + * 重置密码 + * + * @param newPassword 旧密码 + * @param oldPassword 新密码 + */ + @Log(title = "个人信息", businessType = BusinessType.UPDATE) + @PutMapping("/updatePwd") + public R updatePwd(String oldPassword, String newPassword) { + SysUser user = userService.selectUserById(LoginHelper.getUserId()); + String userName = user.getUserName(); + String password = user.getPassword(); + if (!BCrypt.checkpw(oldPassword, password)) { + return R.fail("修改密码失败,旧密码错误"); + } + if (BCrypt.checkpw(newPassword, password)) { + return R.fail("新密码不能与旧密码相同"); + } + + if (userService.resetUserPwd(userName, BCrypt.hashpw(newPassword)) > 0) { + return R.ok(); + } + return R.fail("修改密码异常,请联系管理员"); + } + + /** + * 头像上传 + * + * @param avatarfile 用户头像 + */ + @Log(title = "用户头像", businessType = BusinessType.UPDATE) + @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) { + Map ajax = new HashMap<>(); + if (!avatarfile.isEmpty()) { + String extension = FileUtil.extName(avatarfile.getOriginalFilename()); + if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) { + return R.fail("文件格式不正确,请上传" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "格式"); + } + SysOssVo oss = iSysOssService.upload(avatarfile); + String avatar = oss.getUrl(); + if (userService.updateUserAvatar(getUsername(), avatar)) { + ajax.put("imgUrl", avatar); + return R.ok(ajax); + } + } + return R.fail("上传图片异常,请联系管理员"); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysRegisterController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysRegisterController.java new file mode 100644 index 0000000..3ce454b --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysRegisterController.java @@ -0,0 +1,113 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaIgnore; +import com.alibaba.fastjson.JSON; +import com.zhi.common.annotation.AccessLimit; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.model.RegisterBody; +import com.zhi.common.exception.base.BaseException; +import com.zhi.system.domain.vo.UserVO; +import com.zhi.system.dto.EmailDTO; +import com.zhi.system.service.ISysConfigService; +import com.zhi.system.service.RedisService; +import com.zhi.system.service.SysRegisterService; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static com.zhi.common.constant.blog.MQPrefixConst.EMAIL_EXCHANGE; +import static com.zhi.common.constant.blog.RedisPrefixConst.CODE_EXPIRE_TIME; +import static com.zhi.common.constant.blog.RedisPrefixConst.USER_CODE_KEY; +import static com.zhi.common.utils.blog.CommonUtils.checkEmail; +import static com.zhi.common.utils.blog.CommonUtils.getRandomCode; + +/** + * 注册验证 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +public class SysRegisterController extends BaseController { + + private final SysRegisterService registerService; + private final ISysConfigService configService; + + @Resource + private RabbitTemplate rabbitTemplate; + + + @Resource + private RedisService redisService; + + /** + * 用户注册 + */ + @SaIgnore + @PostMapping("/register") + public R register(@Validated @RequestBody RegisterBody user) { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { + return R.fail("当前系统没有开启注册功能!"); + } + registerService.register(user); + return R.ok(); + } + + + /** + * 前台用户注册邮箱验证码检测 + */ + @SaIgnore + @AccessLimit(seconds = 60, maxCount = 1) + @ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String") + @GetMapping("/users/code") + public R sendCode(String email) { + // 校验邮箱是否合法 + if (!checkEmail(email)) { + throw new BaseException("请输入正确邮箱"); + } + // 生成六位随机验证码发送 + String code = getRandomCode(); + // 发送验证码 + EmailDTO emailDTO = EmailDTO.builder() + .email(email) + .subject("验证码") + .content("您的验证码为 " + code + " 有效期15分钟,请不要告诉他人哦!") + .build(); + rabbitTemplate.convertAndSend(EMAIL_EXCHANGE, "",new Message(JSON.toJSONBytes(emailDTO), new MessageProperties())); + // 将验证码存入redis,设置过期时间为15分钟 + redisService.set(USER_CODE_KEY + email, code, CODE_EXPIRE_TIME); + return R.ok(); + } + + + /** + * 前台用户注册 + * + * @param user 用户信息 + * @return {@link R<>} + */ + @SaIgnore + @ApiOperation(value = "用户注册") + @PostMapping("/blog/register") + public R register(@Valid @RequestBody UserVO user) { + registerService.blogregister(user); + return R.ok(); + } + + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysRoleController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysRoleController.java new file mode 100644 index 0000000..8a53f25 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysRoleController.java @@ -0,0 +1,237 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.util.ObjectUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysDept; +import com.zhi.common.core.domain.entity.SysRole; +import com.zhi.common.core.domain.entity.SysUser; +import com.zhi.common.core.domain.model.LoginUser; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.helper.LoginHelper; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.domain.SysUserRole; +import com.zhi.system.service.ISysDeptService; +import com.zhi.system.service.ISysRoleService; +import com.zhi.system.service.ISysUserService; +import com.zhi.system.service.SysPermissionService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 角色信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/role") +public class SysRoleController extends BaseController { + + private final ISysRoleService roleService; + private final ISysUserService userService; + private final ISysDeptService deptService; + private final SysPermissionService permissionService; + + /** + * 获取角色信息列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/list") + public TableDataInfo list(SysRole role, PageQuery pageQuery) { + return roleService.selectPageRoleList(role, pageQuery); + } + + /** + * 导出角色信息列表 + */ + @Log(title = "角色管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:role:export") + @PostMapping("/export") + public void export(SysRole role, HttpServletResponse response) { + List list = roleService.selectRoleList(role); + ExcelUtil.exportExcel(list, "角色数据", SysRole.class, response); + } + + /** + * 根据角色编号获取详细信息 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:query") + @GetMapping(value = "/{roleId}") + public R getInfo(@PathVariable Long roleId) { + roleService.checkRoleDataScope(roleId); + return R.ok(roleService.selectRoleById(roleId)); + } + + /** + * 新增角色 + */ + @SaCheckPermission("system:role:add") + @Log(title = "角色管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysRole role) { + if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) { + return R.fail("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + return toAjax(roleService.insertRole(role)); + + } + + /** + * 修改保存角色 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); + } else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role))) { + return R.fail("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); + } + + if (roleService.updateRole(role) > 0) { + // 更新缓存用户权限 + LoginUser loginUser = getLoginUser(); + SysUser sysUser = userService.selectUserById(loginUser.getUserId()); + if (ObjectUtil.isNotNull(sysUser) && !sysUser.isAdmin()) { + loginUser.setMenuPermission(permissionService.getMenuPermission(sysUser)); + LoginHelper.setLoginUser(loginUser); + } + return R.ok(); + } + return R.fail("修改角色'" + role.getRoleName() + "'失败,请联系管理员"); + } + + /** + * 修改保存数据权限 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/dataScope") + public R dataScope(@RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.authDataScope(role)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysRole role) { + roleService.checkRoleAllowed(role); + roleService.checkRoleDataScope(role.getRoleId()); + return toAjax(roleService.updateRoleStatus(role)); + } + + /** + * 删除角色 + * + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:role:remove") + @Log(title = "角色管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{roleIds}") + public R remove(@PathVariable Long[] roleIds) { + return toAjax(roleService.deleteRoleByIds(roleIds)); + } + + /** + * 获取角色选择框列表 + */ + @SaCheckPermission("system:role:query") + @GetMapping("/optionselect") + public R> optionselect() { + return R.ok(roleService.selectRoleAll()); + } + + /** + * 查询已分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/allocatedList") + public TableDataInfo allocatedList(SysUser user, PageQuery pageQuery) { + return userService.selectAllocatedList(user, pageQuery); + } + + /** + * 查询未分配用户角色列表 + */ + @SaCheckPermission("system:role:list") + @GetMapping("/authUser/unallocatedList") + public TableDataInfo unallocatedList(SysUser user, PageQuery pageQuery) { + return userService.selectUnallocatedList(user, pageQuery); + } + + /** + * 取消授权用户 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancel") + public R cancelAuthUser(@RequestBody SysUserRole userRole) { + return toAjax(roleService.deleteAuthUser(userRole)); + } + + /** + * 批量取消授权用户 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/cancelAll") + public R cancelAuthUserAll(Long roleId, Long[] userIds) { + return toAjax(roleService.deleteAuthUsers(roleId, userIds)); + } + + /** + * 批量选择用户授权 + * + * @param roleId 角色ID + * @param userIds 用户ID串 + */ + @SaCheckPermission("system:role:edit") + @Log(title = "角色管理", businessType = BusinessType.GRANT) + @PutMapping("/authUser/selectAll") + public R selectAuthUserAll(Long roleId, Long[] userIds) { + roleService.checkRoleDataScope(roleId); + return toAjax(roleService.insertAuthUsers(roleId, userIds)); + } + + /** + * 获取对应角色部门树列表 + * + * @param roleId 角色ID + */ + @SaCheckPermission("system:role:list") + @GetMapping(value = "/deptTree/{roleId}") + public R> roleDeptTreeselect(@PathVariable("roleId") Long roleId) { + Map ajax = new HashMap<>(); + ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId)); + ajax.put("depts", deptService.selectDeptTreeList(new SysDept())); + return R.ok(ajax); + } +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysUserController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysUserController.java new file mode 100644 index 0000000..00f22d2 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysUserController.java @@ -0,0 +1,270 @@ +package com.zhi.web.controller.system; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.secure.BCrypt; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysDept; +import com.zhi.common.core.domain.entity.SysRole; +import com.zhi.common.core.domain.entity.SysUser; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.excel.ExcelResult; +import com.zhi.common.helper.LoginHelper; +import com.zhi.common.utils.StreamUtils; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.system.domain.vo.SysUserExportVo; +import com.zhi.system.domain.vo.SysUserImportVo; +import com.zhi.system.domain.vo.UserInfoVO; +import com.zhi.system.listener.SysUserImportListener; +import com.zhi.system.service.ISysDeptService; +import com.zhi.system.service.ISysPostService; +import com.zhi.system.service.ISysRoleService; +import com.zhi.system.service.ISysUserService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 用户信息 + * + * @author Lion Li + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/user") +public class SysUserController extends BaseController { + + private final ISysUserService userService; + private final ISysRoleService roleService; + private final ISysPostService postService; + private final ISysDeptService deptService; + + + /** + * 博客前台用户修改信息 + */ + @SaIgnore + @PutMapping("/users/info") + public R BlogupdateUserInfo(@Valid @RequestBody UserInfoVO userInfoVO){ + userService.updateBlogUserInfo(userInfoVO); + return R.ok(); + } + + + + + /** + * 获取用户列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/list") + public TableDataInfo list(SysUser user, PageQuery pageQuery) { + return userService.selectPageUserList(user, pageQuery); + } + + /** + * 导出用户列表 + */ + @Log(title = "用户管理", businessType = BusinessType.EXPORT) + @SaCheckPermission("system:user:export") + @PostMapping("/export") + public void export(SysUser user, HttpServletResponse response) { + List list = userService.selectUserList(user); + List listVo = BeanUtil.copyToList(list, SysUserExportVo.class); + for (int i = 0; i < list.size(); i++) { + SysDept dept = list.get(i).getDept(); + SysUserExportVo vo = listVo.get(i); + if (ObjectUtil.isNotEmpty(dept)) { + vo.setDeptName(dept.getDeptName()); + vo.setLeader(dept.getLeader()); + } + } + ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); + } + + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); + return R.ok(result.getAnalysis()); + } + + /** + * 获取导入模板 + */ + @PostMapping("/importTemplate") + public void importTemplate(HttpServletResponse response) { + ExcelUtil.exportExcel(new ArrayList<>(), "用户数据", SysUserImportVo.class, response); + } + + /** + * 根据用户编号获取详细信息 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping(value = {"/", "/{userId}"}) + public R> getInfo(@PathVariable(value = "userId", required = false) Long userId) { + userService.checkUserDataScope(userId); + Map ajax = new HashMap<>(); + List roles = roleService.selectRoleAll(); + ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin())); + ajax.put("posts", postService.selectPostAll()); + if (ObjectUtil.isNotNull(userId)) { + SysUser sysUser = userService.selectUserById(userId); + ajax.put("user", sysUser); + ajax.put("postIds", postService.selectPostListByUserId(userId)); + ajax.put("roleIds", StreamUtils.toList(sysUser.getRoles(), SysRole::getRoleId)); + } + return R.ok(ajax); + } + + /** + * 新增用户 + */ + @SaCheckPermission("system:user:add") + @Log(title = "用户管理", businessType = BusinessType.INSERT) + @PostMapping + public R add(@Validated @RequestBody SysUser user) { + if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) { + return R.fail("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) + && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { + return R.fail("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) + && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { + return R.fail("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.insertUser(user)); + } + + /** + * 修改用户 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping + public R edit(@Validated @RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) { + return R.fail("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); + } else if (StringUtils.isNotEmpty(user.getPhonenumber()) + && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { + return R.fail("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); + } else if (StringUtils.isNotEmpty(user.getEmail()) + && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { + return R.fail("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); + } + return toAjax(userService.updateUser(user)); + } + + /** + * 删除用户 + * + * @param userIds 角色ID串 + */ + @SaCheckPermission("system:user:remove") + @Log(title = "用户管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{userIds}") + public R remove(@PathVariable Long[] userIds) { + if (ArrayUtil.contains(userIds, getUserId())) { + return R.fail("当前用户不能删除"); + } + return toAjax(userService.deleteUserByIds(userIds)); + } + + /** + * 重置密码 + */ + @SaCheckPermission("system:user:resetPwd") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/resetPwd") + public R resetPwd(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + user.setPassword(BCrypt.hashpw(user.getPassword())); + return toAjax(userService.resetPwd(user)); + } + + /** + * 状态修改 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public R changeStatus(@RequestBody SysUser user) { + userService.checkUserAllowed(user); + userService.checkUserDataScope(user.getUserId()); + return toAjax(userService.updateUserStatus(user)); + } + + /** + * 根据用户编号获取授权角色 + * + * @param userId 用户ID + */ + @SaCheckPermission("system:user:query") + @GetMapping("/authRole/{userId}") + public R> authRole(@PathVariable Long userId) { + SysUser user = userService.selectUserById(userId); + List roles = roleService.selectRolesByUserId(userId); + Map ajax = new HashMap<>(); + ajax.put("user", user); + ajax.put("roles", LoginHelper.isAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isAdmin())); + return R.ok(ajax); + } + + /** + * 用户授权角色 + * + * @param userId 用户Id + * @param roleIds 角色ID串 + */ + @SaCheckPermission("system:user:edit") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PutMapping("/authRole") + public R insertAuthRole(Long userId, Long[] roleIds) { + userService.checkUserDataScope(userId); + userService.insertUserAuth(userId, roleIds); + return R.ok(); + } + + /** + * 获取部门树列表 + */ + @SaCheckPermission("system:user:list") + @GetMapping("/deptTree") + public R>> deptTree(SysDept dept) { + return R.ok(deptService.selectDeptTreeList(dept)); + } + +} diff --git a/zhi-admin/src/main/java/com/zhi/web/controller/system/SysUserOauthController.java b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysUserOauthController.java new file mode 100644 index 0000000..1908521 --- /dev/null +++ b/zhi-admin/src/main/java/com/zhi/web/controller/system/SysUserOauthController.java @@ -0,0 +1,104 @@ +package com.zhi.web.controller.system; +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSON; +import com.xkcoding.justauth.AuthRequestFactory; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.entity.SysUser; +import com.zhi.common.core.domain.model.BlogLoginUser; +import com.zhi.common.utils.BeanCopyUtils; +import com.zhi.common.utils.StringUtils; +import com.zhi.system.service.SysLoginService; +import com.zhi.system.service.SysRegisterService; +import io.undertow.servlet.spec.HttpServletResponseImpl; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.config.AuthSource; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 第三方登录 + * @author ftz-lover + * @version 1.0 + * @date 2023/1/20 15:05 + */ +@SaIgnore +@Slf4j +@RestController +@RequestMapping("/oauth") +@RequiredArgsConstructor(onConstructor_ = @Autowired) +public class SysUserOauthController { + + + private final AuthRequestFactory factory; + + private final SysRegisterService registerService; + + + private final SysLoginService loginService; + + + /** + * 登录类型 + */ + @GetMapping + public Map loginType() { + List oauthList = factory.oauthList(); + return oauthList.stream().collect(Collectors + .toMap(oauth -> oauth.toLowerCase() + "登录", + oauth -> "http://127.0.0.1:8080/oauth/login/" + oauth.toLowerCase())); + } + /** + * 返回给前端回调地址 + * + * @param response response + * @throws IOException + */ + + @GetMapping("/login/{type}") + public R login(@PathVariable String type, HttpServletResponse response) throws IOException { + AuthRequest authRequest = factory.get(type); + String authorizeUrl = authRequest.authorize(AuthStateUtils.createState()); + return R.ok("请求成功",authorizeUrl); + } + + /** + * 登录成功后的回调 + * + * @return 登录成功后的信息 + */ + @SaIgnore + @RequestMapping("/{type}/callback") + public void login(@PathVariable String type, AuthCallback callback , HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException { + AuthRequest authRequest = factory.get(type); + AuthResponse authResponse = authRequest.login(callback); + String s = JSONUtil.toJsonStr(authResponse.getData()); + SysUser sysUser = JSON.parseObject(s,SysUser.class); + BlogLoginUser blogLoginUser = registerService.OauthRegister(sysUser); + httpServletResponse.sendRedirect("http://localhost:8081/oauth/login/gitee?userid="+blogLoginUser.getId()); + + } + + + + + + + + +} diff --git a/zhi-admin/src/main/resources/application-dev.yml b/zhi-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..1e8aa29 --- /dev/null +++ b/zhi-admin/src/main/resources/application-dev.yml @@ -0,0 +1,172 @@ + +--- # xxl-job 配置 +xxl.job: + # 执行器开关 + enabled: false + # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 + admin-addresses: http://localhost:9100/xxl-job-admin + # 执行器通讯TOKEN:非空时启用 + access-token: xxl-job + executor: + # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册 + appname: xxl-job-executor + # 执行器端口号 执行器从9101开始往后写 + port: 9101 + # 执行器注册:默认IP:PORT + address: + # 执行器IP:默认自动获取IP + ip: + # 执行器运行日志文件存储磁盘路径 + logpath: ./logs/xxl-job + # 执行器日志文件保存天数:大于3生效 + logretentiondays: 30 + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: true + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://localhost:3306/ry-vue-blog?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + username: root + password: root + # 从库数据源 +# slave: +# lazy: true +# type: ${spring.datasource.type} +# 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&rewriteBatchedStatements=true +# username: +# password: +# oracle: +# type: ${spring.datasource.type} +# driverClassName: oracle.jdbc.OracleDriver +# url: jdbc:oracle:thin:@//localhost:1521/XE +# username: ROOT +# password: root +# hikari: +# connectionTestQuery: SELECT 1 FROM DUAL +# postgres: +# type: ${spring.datasource.type} +# driverClassName: org.postgresql.Driver +# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true +# username: root +# password: root +# sqlserver: +# type: ${spring.datasource.type} +# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver +# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true +# username: SA +# password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 10000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 60000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 900000 + # 连接测试query(配置检测连接是否有效) + connectionTestQuery: SELECT 1 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring: + redis: + # 地址 + host: localhost + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码(如没有密码请注释掉) + # password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + # mq配置 + rabbitmq: + host: 127.0.0.1 + port: 5672 + username: guest + password: guest + listener: + simple: + retry: + enabled: true + max-attempts: 3 #最大重试次数 + initial-interval: 3000 #重试间隔时间(单位毫秒) + +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: true + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true + # 发送方,遵循RFC-822标准 + from: 18835400919@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: 18835400919@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 + +--- # sms 短信 +sms: + enabled: false + # 阿里云 dysmsapi.aliyuncs.com + # 腾讯云 sms.tencentcloudapi.com + endpoint: "dysmsapi.aliyuncs.com" + accessKeyId: xxxxxxx + accessKeySecret: xxxxxx + signName: 测试 + # 腾讯专用 + sdkAppId: diff --git a/zhi-admin/src/main/resources/application-prod.yml b/zhi-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..bd55e65 --- /dev/null +++ b/zhi-admin/src/main/resources/application-prod.yml @@ -0,0 +1,174 @@ +--- # 临时文件存储位置 避免临时文件被系统清理报错 +spring.servlet.multipart.location: /ruoyi/server/temp +--- # xxl-job 配置 +xxl.job: + # 执行器开关 + enabled: false + # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 + admin-addresses: http://xxxx/xxl-job-admin + # 执行器通讯TOKEN:非空时启用 + access-token: xxl-job + executor: + # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册 + appname: xxl-job-executor + # 执行器端口号 执行器从9101开始往后写 + port: 9101 + # 执行器注册:默认IP:PORT + address: + # 执行器IP:默认自动获取IP + ip: + # 执行器运行日志文件存储磁盘路径 + logpath: ./logs/xxl-job + # 执行器日志文件保存天数:大于3生效 + logretentiondays: 30 + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://xxxx:3306/ry-vue-blog?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + username: root + password: root + # 从库数据源 +# slave: +# lazy: true +# type: ${spring.datasource.type} +# driverClassName: com.mysql.cj.jdbc.Driver +# url: jdbc:mysql://8.130.45.202:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true +# username: +# password: +# oracle: +# type: ${spring.datasource.type} +# driverClassName: oracle.jdbc.OracleDriver +# url: jdbc:oracle:thin:@//localhost:1521/XE +# username: ROOT +# password: root +# hikari: +# connectionTestQuery: SELECT 1 FROM DUAL +# postgres: +# type: ${spring.datasource.type} +# driverClassName: org.postgresql.Driver +# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true +# username: root +# password: root +# sqlserver: +# type: ${spring.datasource.type} +# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver +# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true +# username: SA +# password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 10000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 60000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 900000 + # 连接测试query(配置检测连接是否有效) + connectionTestQuery: SELECT 1 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring: + redis: + # 地址 + host: xxxx + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码(如没有密码请注释掉) + password: redis + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + # mq配置 + rabbitmq: + host: xxxx + port: 5672 + username: guest + password: guest + listener: + simple: + retry: + enabled: true + max-attempts: 3 #最大重试次数 + initial-interval: 3000 #重试间隔时间(单位毫秒) + +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: true + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true + # 发送方,遵循RFC-822标准 + from: 18835400919@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: 18835400919@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 + + +--- # sms 短信 +sms: + enabled: false + # 阿里云 dysmsapi.aliyuncs.com + # 腾讯云 sms.tencentcloudapi.com + endpoint: "dysmsapi.aliyuncs.com" + accessKeyId: xxxxxxx + accessKeySecret: xxxxxx + signName: 测试 + # 腾讯专用 + sdkAppId: diff --git a/zhi-admin/src/main/resources/application.yml b/zhi-admin/src/main/resources/application.yml new file mode 100644 index 0000000..1152069 --- /dev/null +++ b/zhi-admin/src/main/resources/application.yml @@ -0,0 +1,406 @@ +# 项目相关配置 +ruoyi: + # 名称 + name: RuoYi-Vue-Plus + # 版本 + version: ${zhi-vue-plus.version} + # 版权年份 + copyrightYear: 2022 + # 实例演示开关 + demoEnabled: true + # 获取ip地址开关 + addressEnabled: true + # 缓存懒加载 + cacheLazy: false + +captcha: + # 页面 <参数设置> 可开启关闭 验证码校验 + # 验证码类型 math 数组计算 char 字符验证 + type: MATH + # line 线段干扰 circle 圆圈干扰 shear 扭曲干扰 + category: CIRCLE + # 数字验证码位数 + numberLength: 1 + # 字符验证码长度 + charLength: 4 + +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8080 + servlet: + # 应用的访问路径 + context-path: / + # undertow 配置 + undertow: + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 + max-http-post-size: -1 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分 + buffer-size: 512 + # 是否分配的直接内存 + direct-buffers: true + threads: + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 + io: 8 + # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 + worker: 256 + +# 日志配置 +logging: + level: + com.zhi: @logging.level@ + org.springframework: warn + config: classpath:logback.xml + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# Spring配置 +spring: + application: + name: ${ruoyi.name} + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: @profiles.active@ + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 10MB + # 设置总上传的文件大小 + max-request-size: 20MB + # 服务模块 + devtools: + restart: + # 热部署开关 + enabled: true + jackson: + # 日期格式化 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + # 格式化输出 + indent_output: false + # 忽略无法转换的对象 + fail_on_empty_beans: false + deserialization: + # 允许对象忽略json中不存在的属性 + fail_on_unknown_properties: false + + # es配置 若搜索模式为mysql可删除 + # 邮箱配置 在dev环境mail中配置邮箱信息,这里先注释! +# mail: +# host: smtp.qq.com +# username: 2831826106@qq.com +# password: xxxxxxxx +# default-encoding: UTF-8 +# port: 587 +# properties: +# mail: +# smtp: +# auth: true +# socketFactory: +# class: javax.net.ssl.SSLSocketFactory +management: + health: + elasticsearch: + enabled: false + + +# 搜索模式 可选 elasticsearch或mysql +search: + mode: mysql + +easy-es: + enable: false # 是否开启EE自动配置 true同时需要取消注释EsSearchStrategyImpl这个类 + address : 127.0.0.1:9200 #填你的es连接地址 + # username: 有设置才填写,非必须 + # password: 有设置才填写,非必须 + db-config: + map-underscore-to-camel-case: false # 是否开启下划线转驼峰 默认为false + + +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # token有效期 设为一天 (必定过期) 单位: 秒 + timeout: 86400 + # token临时有效期 (指定时间无操作就过期) 单位: 秒 + activity-timeout: 1800 + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # 是否尝试从header里读取token + is-read-header: true + # 是否尝试从cookie里读取token + is-read-cookie: false + # token前缀 + token-prefix: "Bearer" + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + +# security配置 +security: + # 排除路径 + excludes: + # 静态资源 + - /*.html + - /**/*.html + - /**/*.css + - /**/*.js + # swagger 文档配置 + - /favicon.ico + - /*/api-docs + - /*/api-docs/** + - /websocket/** + anonymous: + # WebSocket + - /websocket/** + + + + +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 不支持多包, 如有需要可在注解配置 或 提升扫包等级 + # 例如 com.**.**.mapper + mapperPackage: com.zhi.**.mapper + # 对应的 XML 文件位置 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: com.zhi.**.domain + # 启动时是否检查 MyBatis XML 文件的存在,默认不检查 + checkConfigLocation: false + configuration: + # 自动驼峰命名规则(camel case)映射 + mapUnderscoreToCamelCase: true + # MyBatis 自动映射策略 + # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射 + autoMappingBehavior: PARTIAL + # MyBatis 自动映射时未知列或未知属性处理策 + # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息 + autoMappingUnknownColumnBehavior: NONE + # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl + # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl + # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl + logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl + global-config: + # 是否打印 Logo banner + banner: true + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + idType: ASSIGN_ID + # 逻辑已删除值 + logicDeleteValue: 2 + # 逻辑未删除值 + logicNotDeleteValue: 0 + # 字段验证策略之 insert,在 insert 的时候的字段验证策略 + # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL + insertStrategy: NOT_NULL + # 字段验证策略之 update,在 update 的时候的字段验证策略 + updateStrategy: NOT_NULL + # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件 + where-strategy: NOT_NULL + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true + info: + # 标题 + title: '标题:${ruoyi.name}后台管理系统_接口文档' + # 描述 + description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' + # 版本 + version: '版本号: ${zhi-vue-plus.version}' + # 作者信息 + contact: + name: water-zhi + email: 2831826106@qq.com + url: https://gitee.com/JavaLionLi/RuoYi-Vue-Plus + components: + # 鉴权方式配置 + security-schemes: + apiKey: + type: APIKEY + in: HEADER + name: ${sa-token.token-name} + +springdoc: + #这里定义了两个分组,可定义多个,也可以不定义 + group-configs: + - group: 1.演示模块 + packages-to-scan: com.zhi.demo + - group: 2.系统模块 + packages-to-scan: com.zhi.web + - group: 3.代码生成模块 + packages-to-scan: com.zhi.generator + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接(多个用逗号分隔) + excludes: /system/notice + # 匹配链接 + urlPatterns: /system/*,/monitor/*,/tool/* + +# 全局线程池相关配置 +thread-pool: + # 是否开启线程池 + enabled: false + # 队列最大长度 + queueCapacity: 128 + # 线程池维护线程所允许的空闲时间 + keepAliveSeconds: 300 + +--- # 分布式锁 lock4j 全局配置 +lock4j: + # 获取分布式锁超时时间,默认为 3000 毫秒 + acquire-timeout: 3000 + # 分布式锁的超时时间,默认为 30 秒 + expire: 30000 + + +justauth: + enabled: true + type: + QQ: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback + union-id: false + WEIBO: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/weibo/callback + GITEE: + client-id: 81c260182bd4ab80d32aaea0e8c0635a58ff815fce6931229ef91d96e0df4889 + client-secret: 101568b287227064875b90f8268b7598af84939479d0ef8ffeb45382f3b33a78 + redirect-uri: http://127.0.0.1:8080/oauth/gitee/callback + DINGTALK: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/dingtalk/callback + BAIDU: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/baidu/callback + CSDN: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/csdn/callback + CODING: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/coding/callback + domain-prefix: xx + OSCHINA: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/oschina/callback + ALIPAY: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/alipay/callback + alipay-public-key: MIIB**************DAQAB + WECHAT_OPEN: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_open/callback + WECHAT_MP: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_mp/callback + WECHAT_ENTERPRISE: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_enterprise/callback + agent-id: 1000002 + TAOBAO: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/taobao/callback + GOOGLE: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/google/callback + FACEBOOK: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/facebook/callback + DOUYIN: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/douyin/callback + LINKEDIN: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/linkedin/callback + MICROSOFT: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/microsoft/callback + MI: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/mi/callback + TOUTIAO: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/toutiao/callback + TEAMBITION: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/teambition/callback + RENREN: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/renren/callback + PINTEREST: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/pinterest/callback + STACK_OVERFLOW: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/stack_overflow/callback + stack-overflow-key: asd*********asd + HUAWEI: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/huawei/callback + KUJIALE: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/kujiale/callback + GITLAB: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/gitlab/callback + MEITUAN: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/meituan/callback + ELEME: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/eleme/callback + TWITTER: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: http://oauth.xkcoding.com/demo/oauth/twitter/callback + cache: + type: default diff --git a/zhi-admin/src/main/resources/banner.txt b/zhi-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..33fb0ed --- /dev/null +++ b/zhi-admin/src/main/resources/banner.txt @@ -0,0 +1,19 @@ +Application Version: ${zhi-vue-plus.version} +Spring Boot Version: ${spring-boot.version} + ______ + L,. ', + \ ',_ F-16C In flight + external FuelTank + \ @ ', + \ ^~^ ', + \ NR ', + \___'98fw ',_ _..----.._ + [______ "'==.I\_____________..--"<__\\_n@___4\,_ + ,..-=T __ ____________ \/ "'" 0<== "'-+.._ + I____|_____ }_>=========I>=**""''==-------------==- " | "'-.,___ + [_____,.--'" ""--=<""-----=====+==--''"" + ""'-=+..,,__,-----,_____ -=* | + |__ /-----'#------.,I_---------'" + """"'--..__ _.> + ""'''''"" + + -- by Water -之 diff --git a/zhi-admin/src/main/resources/i18n/messages.properties b/zhi-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..e1423a8 --- /dev/null +++ b/zhi-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,45 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{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}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{0}分钟 +xcx.code.not.blank=小程序code不能为空 diff --git a/zhi-admin/src/main/resources/i18n/messages_en_US.properties b/zhi-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..04a4aa3 --- /dev/null +++ b/zhi-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,45 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +user.not.exists=Sorry, your account: {0} does not exist +user.password.not.match=User does not exist/Password error +user.password.retry.limit.count=Password input error {0} times +user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes +user.password.delete=Sorry, your account:{0} has been deleted +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator +role.blocked=Role disabled,please contact administrators +user.logout.success=Exit successful +length.not.valid=The length must be between {min} and {max} characters +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.email.not.valid=Mailbox format error +user.phonenumber.not.blank=Phone number cannot be blank +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] +repeat.submit.message=Repeat submit is not allowed, please try again later +rate.limiter.message=Visit too frequently, please try again later +sms.code.not.blank=Sms code cannot be blank +sms.code.retry.limit.count=Sms code input error {0} times +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {0} minutes +xcx.code.not.blank=Mini program code cannot be blank diff --git a/zhi-admin/src/main/resources/i18n/messages_zh_CN.properties b/zhi-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..e1423a8 --- /dev/null +++ b/zhi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,45 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,帐户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{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}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{0}分钟 +xcx.code.not.blank=小程序code不能为空 diff --git a/zhi-admin/src/main/resources/logback.xml b/zhi-admin/src/main/resources/logback.xml new file mode 100644 index 0000000..40fa33b --- /dev/null +++ b/zhi-admin/src/main/resources/logback.xml @@ -0,0 +1,129 @@ + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + ${log.path}/sys-console.log + + + ${log.path}/sys-console.%d{yyyy-MM-dd}.log + + 1 + + + ${log.pattern} + utf-8 + + + + INFO + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + 0 + + 512 + + + + + + + + 0 + + 512 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zhi-admin/src/main/resources/spy.properties b/zhi-admin/src/main/resources/spy.properties new file mode 100644 index 0000000..abbd893 --- /dev/null +++ b/zhi-admin/src/main/resources/spy.properties @@ -0,0 +1,28 @@ +# p6spy 性能分析插件配置文件 +modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory +# 自定义日志打印 +logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger +#日志输出到控制台 +appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger +# 使用日志系统记录 sql +#appender=com.p6spy.engine.spy.appender.Slf4JLogger +# 设置 p6spy driver 代理 +#deregisterdrivers=true +# 取消JDBC URL前缀 +useprefix=true +# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. +excludecategories=info,debug,result,commit,resultset +# 日期格式 +dateformat=yyyy-MM-dd HH:mm:ss +# SQL语句打印时间格式 +databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss +# 实际驱动可多个 +#driverlist=org.h2.Driver +# 是否开启慢SQL记录 +outagedetection=true +# 慢SQL记录标准 2 秒 +outagedetectioninterval=2 +# 是否过滤 Log +filter=true +# 过滤 Log 时所排除的 sql 关键字,以逗号分隔 +exclude=SELECT 1 diff --git a/zhi-blog-plus-master/LICENSE b/zhi-blog-plus-master/LICENSE new file mode 100644 index 0000000..32b3071 --- /dev/null +++ b/zhi-blog-plus-master/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2019 RuoYi-Vue-Plus + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/zhi-blog-plus-master/README.md b/zhi-blog-plus-master/README.md new file mode 100644 index 0000000..7f19928 --- /dev/null +++ b/zhi-blog-plus-master/README.md @@ -0,0 +1,124 @@ +## 博客简介 + + +> 使用RuoYi-Vue-Plus 作为博客的后端框架 + +> 项目代码、文档 均开源免费遵循开源协议在项目中保留开源协议文件即可
+ +### 系统演示功能暂未更新到最新代码,具体实现以最新代码效果为准 +### 系统演示出现bug等问题最新仓库代码已解决,请优先关注群内公告更新消息 +### 建议拉取代码后删除sys_oss中的全部代码,不然会影响文件管理页面的访问 +### :演示涉及到文件或者图片上传需要自行修改文件配置模块,写上自己的云端账密,使用后务必记住删除 +### : 演示模式三方登录逻辑暂未体现 +> 系统演示: 前台 http://water-zhi.cn 后台:http://admin.water-zhi.cn +> +> ## 部署博客的操作步骤文章与问题询问请进群:551275273 + +## 业务功能 + +| 功能 | 介绍 | +|---|---| +| 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置。 | +| 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 | +| 岗位管理 | 配置系统用户所属担任职务。 | +| 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等。 | +| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分。 | +| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护。 | +| 参数管理 | 对系统动态配置常用参数。 | +| 通知公告 | 系统通知公告信息发布维护。 | +| 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询。 | +| 登录日志 | 系统登录日志记录查询包含登录异常。 | +| 文件管理 | 系统文件上传、下载等管理。 | +| 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志。 | +| 代码生成 | 前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 | +| 系统接口 | 根据业务代码自动生成相关的api接口文档。 | +| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等。 | +| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | +| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | +| 连接池监视 | 监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 | +| 使用案例 | 系统的一些功能案例 | + +## 博客模块介绍 + +| 包 | 介绍 | +|--|---| +| blogutils | 博客后台中通用的方法。 | +| domain | 实体层 | +| domain-bo | 前端后台管理系统给后端返回的数据(查询条件)。 | +| domain-vo | 后端给前端后台管理系统返回的数据层。 | +| dto | 后端给前端前台界面返回的数据 | +| dto-vo | 前端的前台界面给后端返回的数据 | +| domain-es | es索引对应查询的实体类 | + +## 博客特点: +- 项目规范,属于企业级博客 +- 鉴权使用了sa-token极大的降低了与项目的耦合度,代替了spring-security +- 标签与分类动态添加 +- 弹幕强留言 +- 文章推荐等功能 +- 多搜索模式 +- 使用just-auth集成三方登录,便于拓展 +- 前台参考"Hexo"的"Butterfly"设计 +- 后台根据ruoyi-vue-plus开发十分贴合企业级开发规范 +- 整合了easy_es mail等流行框架 + +## 使用技术: +### 前端:前端: vue + vuex + vue-router + axios + vuetify + element + echarts +### 后端: SpringBoot + easy_es + nginx + docker + sa-token + Swagger2 + MyBatisPlus + Mysql + Redis + elasticsearch + RabbitMQ + MaxWell + Websocket + + +## 存储:使用当前主流的三方云端,cos/oss/七牛等动态切换 + +## 运行环境:服务器:至少1核2G(关闭es) + + +## 加群与捐献 🐧群:551275273 + + +## 捐献作者 +开源博主创作不易! + + + + + +## 演示图例 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +# 致敬:前端:风神 后端:LionLi+风神 \ No newline at end of file diff --git a/zhi-common/pom.xml b/zhi-common/pom.xml new file mode 100644 index 0000000..2ebb01a --- /dev/null +++ b/zhi-common/pom.xml @@ -0,0 +1,233 @@ + + + + ruoyi-vue-plus + com.zhi + 4.4.0 + + 4.0.0 + + zhi-common + + + common通用工具 + + + + + + + org.springframework + spring-context-support + + + + + org.springframework + spring-web + + + + + cn.dev33 + sa-token-spring-boot-starter + + + + cn.dev33 + sa-token-jwt + + + + + + org.apache.mahout + mahout-mr + 0.12.2 + + + javax.servlet + servlet-api + + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-jcl + + + org.apache.lucene + lucene-core + + + org.apache.lucene + lucene-analyzers-common + + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + jersey-client + com.sun.jersey + + + jersey-core + com.sun.jersey + + + jersey-apache-client4 + com.sun.jersey.contribs + + + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.apache.commons + commons-lang3 + + + + + com.fasterxml.jackson.core + jackson-databind + + + + com.alibaba + easyexcel + + + + + org.yaml + snakeyaml + + + + + javax.servlet + javax.servlet-api + + + + com.baomidou + mybatis-plus-boot-starter + + + com.baomidou + mybatis-plus-extension + + + + + com.baomidou + dynamic-datasource-spring-boot-starter + + + + cn.hutool + hutool-core + + + + cn.hutool + hutool-http + + + + cn.hutool + hutool-captcha + + + + cn.hutool + hutool-jwt + + + + cn.hutool + hutool-extra + + + + com.sun.mail + jakarta.mail + + + + org.projectlombok + lombok + + + + org.springdoc + springdoc-openapi-webmvc-core + + + + org.springdoc + springdoc-openapi-javadoc + + + + + org.springframework.boot + spring-boot-configuration-processor + + + + + org.redisson + redisson-spring-boot-starter + + + + com.baomidou + lock4j-redisson-spring-boot-starter + + + + + cn.easy-es + easy-es-boot-starter + + + + org.springframework.boot + spring-boot-starter-websocket + + + + + + + com.alibaba + fastjson + 1.2.76 + + + + eu.bitwalker + UserAgentUtils + 1.20 + + + + + diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/AccessLimit.java b/zhi-common/src/main/java/com/zhi/common/annotation/AccessLimit.java new file mode 100644 index 0000000..96fe0c1 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/AccessLimit.java @@ -0,0 +1,28 @@ +package com.zhi.common.annotation; + +import java.lang.annotation.*; + +/** + * @author hnz + * @date 2022/3/23 11:16 + * @description redis接口限流 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AccessLimit { + + /** + * 单位时间(秒) + * + * @return int + */ + int seconds(); + + /** + * 单位时间最大请求次数 + * + * @return int + */ + int maxCount(); +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/CellMerge.java b/zhi-common/src/main/java/com/zhi/common/annotation/CellMerge.java new file mode 100644 index 0000000..31cf57e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/CellMerge.java @@ -0,0 +1,24 @@ +package com.zhi.common.annotation; + +import com.zhi.common.excel.CellMergeStrategy; + +import java.lang.annotation.*; + +/** + * excel 列单元格合并(合并列相同项) + * + * 需搭配 {@link CellMergeStrategy} 策略使用 + * + * @author Lion Li + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface CellMerge { + + /** + * col index + */ + int index() default -1; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/DataColumn.java b/zhi-common/src/main/java/com/zhi/common/annotation/DataColumn.java new file mode 100644 index 0000000..bd7d0fa --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/DataColumn.java @@ -0,0 +1,28 @@ +package com.zhi.common.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限 + * + * 一个注解只能对应一个模板 + * + * @author Lion Li + * @version 3.5.0 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataColumn { + + /** + * 占位符关键字 + */ + String[] key() default "deptName"; + + /** + * 占位符替换值 + */ + String[] value() default "dept_id"; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/DataPermission.java b/zhi-common/src/main/java/com/zhi/common/annotation/DataPermission.java new file mode 100644 index 0000000..1b84299 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/DataPermission.java @@ -0,0 +1,18 @@ +package com.zhi.common.annotation; + +import java.lang.annotation.*; + +/** + * 数据权限组 + * + * @author Lion Li + * @version 3.5.0 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + DataColumn[] value(); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/DictDataMapper.java b/zhi-common/src/main/java/com/zhi/common/annotation/DictDataMapper.java new file mode 100644 index 0000000..6c28bd8 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/DictDataMapper.java @@ -0,0 +1,27 @@ +package com.zhi.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.zhi.common.jackson.DictDataJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 字典数据映射注解 + * + * @author itino + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@JacksonAnnotationsInside +@JsonSerialize(using = DictDataJsonSerializer.class) +public @interface DictDataMapper { + + /** + * 设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/ExcelDictFormat.java b/zhi-common/src/main/java/com/zhi/common/annotation/ExcelDictFormat.java new file mode 100644 index 0000000..7ae7ccc --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/ExcelDictFormat.java @@ -0,0 +1,30 @@ +package com.zhi.common.annotation; + +import java.lang.annotation.*; + +/** + * 字典格式化 + * + * @author Lion Li + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ExcelDictFormat { + + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + String readConverterExp() default ""; + + /** + * 分隔符,读取字符串组内容 + */ + String separator() default ","; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/Log.java b/zhi-common/src/main/java/com/zhi/common/annotation/Log.java new file mode 100644 index 0000000..c483a56 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/Log.java @@ -0,0 +1,41 @@ +package com.zhi.common.annotation; + +import com.zhi.common.enums.BusinessType; +import com.zhi.common.enums.OperatorType; + +import java.lang.annotation.*; + +/** + * 自定义操作日志记录注解 + * + * @author ruoyi + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Log { + /** + * 模块 + */ + String title() default ""; + + /** + * 功能 + */ + BusinessType businessType() default BusinessType.OTHER; + + /** + * 操作人类别 + */ + OperatorType operatorType() default OperatorType.MANAGE; + + /** + * 是否保存请求的参数 + */ + boolean isSaveRequestData() default true; + + /** + * 是否保存响应的参数 + */ + boolean isSaveResponseData() default true; +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/RateLimiter.java b/zhi-common/src/main/java/com/zhi/common/annotation/RateLimiter.java new file mode 100644 index 0000000..690799f --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/RateLimiter.java @@ -0,0 +1,36 @@ +package com.zhi.common.annotation; + +import com.zhi.common.constant.CacheConstants; +import com.zhi.common.enums.LimitType; + +import java.lang.annotation.*; + +/** + * 限流注解 + * + * @author Lion Li + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RateLimiter { + /** + * 限流key + */ + String key() default CacheConstants.RATE_LIMIT_KEY; + + /** + * 限流时间,单位秒 + */ + int time() default 60; + + /** + * 限流次数 + */ + int count() default 100; + + /** + * 限流类型 + */ + LimitType limitType() default LimitType.DEFAULT; +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/RepeatSubmit.java b/zhi-common/src/main/java/com/zhi/common/annotation/RepeatSubmit.java new file mode 100644 index 0000000..52a6c3e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/RepeatSubmit.java @@ -0,0 +1,29 @@ +package com.zhi.common.annotation; + +import java.lang.annotation.*; +import java.util.concurrent.TimeUnit; + +/** + * 自定义注解防止表单重复提交 + * + * @author Lion Li + */ +@Inherited +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RepeatSubmit { + + /** + * 间隔时间(ms),小于此时间视为重复提交 + */ + int interval() default 5000; + + TimeUnit timeUnit() default TimeUnit.MILLISECONDS; + + /** + * 提示消息 支持国际化 格式为 {code} + */ + String message() default "{repeat.submit.message}"; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/Sensitive.java b/zhi-common/src/main/java/com/zhi/common/annotation/Sensitive.java new file mode 100644 index 0000000..e1a89ae --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/Sensitive.java @@ -0,0 +1,24 @@ +package com.zhi.common.annotation; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.zhi.common.enums.SensitiveStrategy; +import com.zhi.common.jackson.SensitiveJsonSerializer; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 数据脱敏注解 + * + * @author zhujie + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@JacksonAnnotationsInside +@JsonSerialize(using = SensitiveJsonSerializer.class) +public @interface Sensitive { + SensitiveStrategy strategy(); +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/Translation.java b/zhi-common/src/main/java/com/zhi/common/annotation/Translation.java new file mode 100644 index 0000000..4ecae70 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/Translation.java @@ -0,0 +1,38 @@ +package com.zhi.common.annotation; +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.zhi.common.translation.handler.TranslationHandler; + +import java.lang.annotation.*; + +/** + * 通用翻译注解 + * + * @author Lion Li + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.METHOD}) +@Documented +@JacksonAnnotationsInside +@JsonSerialize(using = TranslationHandler.class) +public @interface Translation { + + /** + * 类型 (需与实现类上的 {@link com.zhi.common.annotation.TranslationType} 注解type对应) + *

+ * 默认取当前字段的值 如果设置了 @{@link Translation#mapper()} 则取映射字段的值 + */ + String type(); + + /** + * 映射字段 (如果不为空则取此字段的值) + */ + String mapper() default ""; + + /** + * 其他条件 例如: 字典type(sys_user_sex) + */ + String other() default ""; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/annotation/TranslationType.java b/zhi-common/src/main/java/com/zhi/common/annotation/TranslationType.java new file mode 100644 index 0000000..a012e8e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/annotation/TranslationType.java @@ -0,0 +1,21 @@ +package com.zhi.common.annotation; + +import java.lang.annotation.*; + +/** + * 翻译类型注解 (标注到{@link com.zhi.common.translation.TranslationInterface} 的实现类) + * + * @author Lion Li + */ +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +@Documented +public @interface TranslationType { + + /** + * 类型 + */ + String type(); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/captcha/UnsignedMathGenerator.java b/zhi-common/src/main/java/com/zhi/common/captcha/UnsignedMathGenerator.java new file mode 100644 index 0000000..1a06bda --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/captcha/UnsignedMathGenerator.java @@ -0,0 +1,85 @@ +package com.zhi.common.captcha; + +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.core.math.Calculator; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.RandomUtil; +import com.zhi.common.utils.StringUtils; + +/** + * 无符号计算生成器 + * + * @author Lion Li + */ +public class UnsignedMathGenerator implements CodeGenerator { + + private static final long serialVersionUID = -5514819971774091076L; + + private static final String OPERATORS = "+-*"; + + /** + * 参与计算数字最大长度 + */ + private final int numberLength; + + /** + * 构造 + */ + public UnsignedMathGenerator() { + this(2); + } + + /** + * 构造 + * + * @param numberLength 参与计算最大数字位数 + */ + public UnsignedMathGenerator(int numberLength) { + this.numberLength = numberLength; + } + + @Override + public String generate() { + final int limit = getLimit(); + int a = RandomUtil.randomInt(limit); + int b = RandomUtil.randomInt(limit); + String max = Integer.toString(Math.max(a,b)); + String min = Integer.toString(Math.min(a,b)); + max = StringUtils.rightPad(max, this.numberLength, CharUtil.SPACE); + min = StringUtils.rightPad(min, this.numberLength, CharUtil.SPACE); + + return max + RandomUtil.randomChar(OPERATORS) + min + '='; + } + + @Override + public boolean verify(String code, String userInputCode) { + int result; + try { + result = Integer.parseInt(userInputCode); + } catch (NumberFormatException e) { + // 用户输入非数字 + return false; + } + + final int calculateResult = (int) Calculator.conversion(code); + return result == calculateResult; + } + + /** + * 获取验证码长度 + * + * @return 验证码长度 + */ + public int getLength() { + return this.numberLength * 2 + 2; + } + + /** + * 根据长度获取参与计算数字最大值 + * + * @return 最大值 + */ + private int getLimit() { + return Integer.parseInt("1" + StringUtils.repeat('0', this.numberLength)); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/config/RuoYiConfig.java b/zhi-common/src/main/java/com/zhi/common/config/RuoYiConfig.java new file mode 100644 index 0000000..e076216 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/config/RuoYiConfig.java @@ -0,0 +1,54 @@ +package com.zhi.common.config; + +import lombok.Data; +import lombok.Getter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 读取项目相关配置 + * + * @author Lion Li + */ + +@Data +@Component +@ConfigurationProperties(prefix = "ruoyi") +public class RuoYiConfig { + + /** + * 项目名称 + */ + private String name; + + /** + * 版本 + */ + private String version; + + /** + * 版权年份 + */ + private String copyrightYear; + + /** + * 实例演示开关 + */ + private boolean demoEnabled; + + /** + * 缓存懒加载 + */ + private boolean cacheLazy; + + /** + * 获取地址开关 + */ + @Getter + private static boolean addressEnabled; + + public void setAddressEnabled(boolean addressEnabled) { + RuoYiConfig.addressEnabled = addressEnabled; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/CacheConstants.java b/zhi-common/src/main/java/com/zhi/common/constant/CacheConstants.java new file mode 100644 index 0000000..e2e39b0 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/CacheConstants.java @@ -0,0 +1,49 @@ +package com.zhi.common.constant; + +/** + * 缓存的key 常量 + * + * @author ruoyi + */ +public interface CacheConstants { + + /** + * 登录用户 redis key + */ + String LOGIN_TOKEN_KEY = "Authorization:login:token:"; + + /** + * 在线用户 redis key + */ + String ONLINE_TOKEN_KEY = "online_tokens:"; + + /** + * 验证码 redis key + */ + String CAPTCHA_CODE_KEY = "captcha_codes:"; + + /** + * 参数管理 cache key + */ + String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache key + */ + String SYS_DICT_KEY = "sys_dict:"; + + /** + * 防重提交 redis key + */ + String REPEAT_SUBMIT_KEY = "repeat_submit:"; + + /** + * 限流 redis key + */ + String RATE_LIMIT_KEY = "rate_limit:"; + + /** + * 登录账户密码错误次数 redis key + */ + String PWD_ERR_CNT_KEY = "pwd_err_cnt:"; +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/CacheNames.java b/zhi-common/src/main/java/com/zhi/common/constant/CacheNames.java new file mode 100644 index 0000000..c44d819 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/CacheNames.java @@ -0,0 +1,58 @@ +package com.zhi.common.constant; + +/** + * 缓存组名称常量 + *

+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize + *

+ * ttl 过期时间 如果设置为0则不过期 默认为0 + * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0 + * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0 + *

+ * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500 + * + * @author Lion Li + */ +public interface CacheNames { + + /** + * 演示案例 + */ + String DEMO_CACHE = "demo:cache#60s#10m#20"; + + /** + * 系统配置 + */ + String SYS_CONFIG = "sys_config"; + + /** + * 数据字典 + */ + String SYS_DICT = "sys_dict"; + + /** + * 用户账户 + */ + String SYS_USER_NAME = "sys_user_name#30d"; + + /** + * 部门 + */ + String SYS_DEPT = "sys_dept#30d"; + + /** + * OSS内容 + */ + String SYS_OSS = "sys_oss#30d"; + + /** + * OSS配置 + */ + String SYS_OSS_CONFIG = "sys_oss_config"; + + /** + * 在线用户 + */ + String ONLINE_TOKEN = "online_tokens"; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/Constants.java b/zhi-common/src/main/java/com/zhi/common/constant/Constants.java new file mode 100644 index 0000000..93dee96 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/Constants.java @@ -0,0 +1,93 @@ +package com.zhi.common.constant; + +/** + * 通用常量信息 + * + * @author ruoyi + */ +public interface Constants { + + + /** + * 初始密码 + */ + String FIRSTPASSWORD = "123456"; + + /** + * 默认sys系统用户注册 + */ + String TYPE = "sys_user"; + + + /** + * 默认注册用户头像 + */ + String AVATAR = "https://s1.ax1x.com/2023/01/15/pSQf91A.jpg"; + + /** + * UTF-8 字符集 + */ + String UTF8 = "UTF-8"; + + /** + * GBK 字符集 + */ + String GBK = "GBK"; + + /** + * www主域 + */ + String WWW = "www."; + + /** + * http请求 + */ + String HTTP = "http://"; + + /** + * https请求 + */ + String HTTPS = "https://"; + + /** + * 通用成功标识 + */ + String SUCCESS = "0"; + + /** + * 通用失败标识 + */ + String FAIL = "1"; + + /** + * 登录成功 + */ + String LOGIN_SUCCESS = "Success"; + + /** + * 注销 + */ + String LOGOUT = "Logout"; + + /** + * 注册 + */ + String REGISTER = "Register"; + + /** + * 登录失败 + */ + String LOGIN_FAIL = "Error"; + + /** + * 验证码有效期(分钟) + */ + Integer CAPTCHA_EXPIRATION = 2; + + /** + * 令牌 + */ + String TOKEN = "token"; + +} + diff --git a/zhi-common/src/main/java/com/zhi/common/constant/GenConstants.java b/zhi-common/src/main/java/com/zhi/common/constant/GenConstants.java new file mode 100644 index 0000000..0b065cc --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/GenConstants.java @@ -0,0 +1,193 @@ +package com.zhi.common.constant; + +/** + * 代码生成通用常量 + * + * @author ruoyi + */ +public interface GenConstants { + /** + * 单表(增删改查) + */ + String TPL_CRUD = "crud"; + + /** + * 树表(增删改查) + */ + String TPL_TREE = "tree"; + + /** + * 主子表(增删改查) + */ + String TPL_SUB = "sub"; + + /** + * 树编码字段 + */ + String TREE_CODE = "treeCode"; + + /** + * 树父编码字段 + */ + String TREE_PARENT_CODE = "treeParentCode"; + + /** + * 树名称字段 + */ + String TREE_NAME = "treeName"; + + /** + * 上级菜单ID字段 + */ + String PARENT_MENU_ID = "parentMenuId"; + + /** + * 上级菜单名称字段 + */ + String PARENT_MENU_NAME = "parentMenuName"; + + /** + * 数据库字符串类型 + */ + String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"}; + + /** + * 数据库文本类型 + */ + String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"}; + + /** + * 数据库时间类型 + */ + String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"}; + + /** + * 数据库数字类型 + */ + String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", + "bit", "bigint", "float", "double", "decimal"}; + + /** + * BO对象 不需要添加字段 + */ + String[] COLUMNNAME_NOT_ADD = {"create_by", "create_time", "del_flag", "update_by", + "update_time", "version"}; + + /** + * BO对象 不需要编辑字段 + */ + String[] COLUMNNAME_NOT_EDIT = {"create_by", "create_time", "del_flag", "update_by", + "update_time", "version"}; + + /** + * VO对象 不需要返回字段 + */ + String[] COLUMNNAME_NOT_LIST = {"create_by", "create_time", "del_flag", "update_by", + "update_time", "version"}; + + /** + * BO对象 不需要查询字段 + */ + String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark", "version"}; + + /** + * Entity基类字段 + */ + String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime"}; + + /** + * Tree基类字段 + */ + String[] TREE_ENTITY = {"parentName", "parentId", "children"}; + + /** + * 文本框 + */ + String HTML_INPUT = "input"; + + /** + * 文本域 + */ + String HTML_TEXTAREA = "textarea"; + + /** + * 下拉框 + */ + String HTML_SELECT = "select"; + + /** + * 单选框 + */ + String HTML_RADIO = "radio"; + + /** + * 复选框 + */ + String HTML_CHECKBOX = "checkbox"; + + /** + * 日期控件 + */ + String HTML_DATETIME = "datetime"; + + /** + * 图片上传控件 + */ + String HTML_IMAGE_UPLOAD = "imageUpload"; + + /** + * 文件上传控件 + */ + String HTML_FILE_UPLOAD = "fileUpload"; + + /** + * 富文本控件 + */ + String HTML_EDITOR = "editor"; + + /** + * 字符串类型 + */ + String TYPE_STRING = "String"; + + /** + * 整型 + */ + String TYPE_INTEGER = "Integer"; + + /** + * 长整型 + */ + String TYPE_LONG = "Long"; + + /** + * 浮点型 + */ + String TYPE_DOUBLE = "Double"; + + /** + * 高精度计算类型 + */ + String TYPE_BIGDECIMAL = "BigDecimal"; + + /** + * 时间类型 + */ + String TYPE_DATE = "Date"; + + /** + * 模糊查询 + */ + String QUERY_LIKE = "LIKE"; + + /** + * 相等查询 + */ + String QUERY_EQ = "EQ"; + + /** + * 需要 + */ + String REQUIRE = "1"; +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/HttpStatus.java b/zhi-common/src/main/java/com/zhi/common/constant/HttpStatus.java new file mode 100644 index 0000000..6a215cd --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/HttpStatus.java @@ -0,0 +1,93 @@ +package com.zhi.common.constant; + +/** + * 返回状态码 + * + * @author Lion Li + */ +public interface HttpStatus { + /** + * 操作成功 + */ + int SUCCESS = 200; + + /** + * 对象创建成功 + */ + int CREATED = 201; + + /** + * 请求已经被接受 + */ + int ACCEPTED = 202; + + /** + * 操作已经执行成功,但是没有返回数据 + */ + int NO_CONTENT = 204; + + /** + * 资源已被移除 + */ + int MOVED_PERM = 301; + + /** + * 重定向 + */ + int SEE_OTHER = 303; + + /** + * 资源没有被修改 + */ + int NOT_MODIFIED = 304; + + /** + * 参数列表错误(缺少,格式不匹配) + */ + int BAD_REQUEST = 400; + + /** + * 未授权 + */ + int UNAUTHORIZED = 401; + + /** + * 访问受限,授权过期 + */ + int FORBIDDEN = 403; + + /** + * 资源,服务未找到 + */ + int NOT_FOUND = 404; + + /** + * 不允许的http方法 + */ + int BAD_METHOD = 405; + + /** + * 资源冲突,或者资源被锁 + */ + int CONFLICT = 409; + + /** + * 不支持的数据,媒体类型 + */ + int UNSUPPORTED_TYPE = 415; + + /** + * 系统内部错误 + */ + int ERROR = 500; + + /** + * 接口未实现 + */ + int NOT_IMPLEMENTED = 501; + + /** + * 系统警告消息 + */ + int WARN = 601; +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/TransConstant.java b/zhi-common/src/main/java/com/zhi/common/constant/TransConstant.java new file mode 100644 index 0000000..d645c77 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/TransConstant.java @@ -0,0 +1,30 @@ +package com.zhi.common.constant; + +/** + * 翻译常量 + * + * @author Lion Li + */ +public interface TransConstant { + + /** + * 用户id转账号 + */ + String USER_ID_TO_NAME = "user_id_to_name"; + + /** + * 部门id转名称 + */ + String DEPT_ID_TO_NAME = "dept_id_to_name"; + + /** + * 字典type转label + */ + String DICT_TYPE_TO_LABEL = "dict_type_to_label"; + + /** + * ossId转url + */ + String OSS_ID_TO_URL = "oss_id_to_url"; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/UserConstants.java b/zhi-common/src/main/java/com/zhi/common/constant/UserConstants.java new file mode 100644 index 0000000..f7baa38 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/UserConstants.java @@ -0,0 +1,138 @@ +package com.zhi.common.constant; + +/** + * 用户常量信息 + * + * @author ruoyi + */ +public interface UserConstants { + + /** + * 平台内系统用户的唯一标志 + */ + String SYS_USER = "SYS_USER"; + + /** + * 正常状态 + */ + String NORMAL = "0"; + + /** + * 异常状态 + */ + String EXCEPTION = "1"; + + /** + * 用户正常状态 + */ + String USER_NORMAL = "0"; + + /** + * 用户封禁状态 + */ + String USER_DISABLE = "1"; + + /** + * 角色正常状态 + */ + String ROLE_NORMAL = "0"; + + /** + * 角色封禁状态 + */ + String ROLE_DISABLE = "1"; + + /** + * 部门正常状态 + */ + String DEPT_NORMAL = "0"; + + /** + * 部门停用状态 + */ + String DEPT_DISABLE = "1"; + + /** + * 字典正常状态 + */ + String DICT_NORMAL = "0"; + + /** + * 是否为系统默认(是) + */ + String YES = "Y"; + + /** + * 是否菜单外链(是) + */ + String YES_FRAME = "0"; + + /** + * 是否菜单外链(否) + */ + String NO_FRAME = "1"; + + /** + * 菜单正常状态 + */ + String MENU_NORMAL = "0"; + + /** + * 菜单停用状态 + */ + String MENU_DISABLE = "1"; + + /** + * 菜单类型(目录) + */ + String TYPE_DIR = "M"; + + /** + * 菜单类型(菜单) + */ + String TYPE_MENU = "C"; + + /** + * 菜单类型(按钮) + */ + String TYPE_BUTTON = "F"; + + /** + * Layout组件标识 + */ + String LAYOUT = "Layout"; + + /** + * ParentView组件标识 + */ + String PARENT_VIEW = "ParentView"; + + /** + * InnerLink组件标识 + */ + String INNER_LINK = "InnerLink"; + + /** + * 校验返回结果码 + */ + String UNIQUE = "0"; + String NOT_UNIQUE = "1"; + + /** + * 用户名长度限制 + */ + int USERNAME_MIN_LENGTH = 2; + int USERNAME_MAX_LENGTH = 20; + + /** + * 密码长度限制 + */ + int PASSWORD_MIN_LENGTH = 5; + int PASSWORD_MAX_LENGTH = 20; + + /** + * 管理员ID + */ + Long ADMIN_ID = 1L; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/blog/CommonConst.java b/zhi-common/src/main/java/com/zhi/common/constant/blog/CommonConst.java new file mode 100644 index 0000000..40c0de9 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/blog/CommonConst.java @@ -0,0 +1,146 @@ +package com.zhi.common.constant.blog; + + +/** + * 公共常量 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +public class CommonConst { + /** + * 文章对应的type + */ + public static final String ARTICLE_TYPE = "articleCommentStrategy"; + + public static final Integer ARTICLE_TYPE_VALUE = 1; + + /** + * 友链对应的type + */ + public static final String FRIENDLINK_TYPE = "friendLinkCommentStrategy"; + + public static final Integer FRIENDLINK_TYPE_VALUE = 2; + + /** + * 说说对应的type + */ + public static final String TALK_TYPE = "talkCommentStrategy"; + + public static final Integer TALK_TYPE_VALUE = 3; + + + + /** + * 默认文章标签/分类 + */ + public static final String DEFAULTCATORTAG = "默认"; + + /** + * 默认文章标签/分类id + */ + + public static final Long DEFAULTCATORTAGID = Long.valueOf(1); + + /** + * 已审核 + */ + public static final int STATE = 1; + + /** + * 系统是 + */ + public static final String YES = "Y"; + + + /** + * 系统否 + */ + public static final String NO = "N"; + + /** + * 对 + */ + public static final String ISTRUE = "true"; + + /** + * 否 + */ + public static final int FALSE = 0; + + /** + * 是 + */ + public static final int TRUE = 1; + + /** + * 高亮标签 + */ + public static final String PRE_TAG = ""; + + /** + * 高亮标签 + */ + public static final String POST_TAG = ""; + + /** + * 当前页码 + */ + public static final String CURRENT = "current"; + + /** + * 页码条数 + */ + public static final String SIZE = "size"; + + /** + * 博主id + */ + public static final Integer BLOGGER_ID = 1; + + /** + * 默认条数 + */ + public static final String DEFAULT_SIZE = "10"; + + /** + * 默认用户昵称 + */ + public static final String DEFAULT_NICKNAME = "用户"; + + /** + * 浏览文章集合 + */ + public static String ARTICLE_SET = "articleSet"; + + /** + * 前端组件名 + */ + public static String COMPONENT = "Layout"; + + /** + * 省 + */ + public static final String PROVINCE = "省"; + + /** + * 市 + */ + public static final String CITY = "市"; + + /** + * 未知的 + */ + public static final String UNKNOWN = "未知"; + + /** + * JSON 格式 + */ + public static final String APPLICATION_JSON = "application/json;charset=utf-8"; + + /** + * 默认的配置id + */ + public static final Integer DEFAULT_CONFIG_ID = 1; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/blog/MQPrefixConst.java b/zhi-common/src/main/java/com/zhi/common/constant/blog/MQPrefixConst.java new file mode 100644 index 0000000..1bc86bd --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/blog/MQPrefixConst.java @@ -0,0 +1,32 @@ +package com.zhi.common.constant.blog; + +/** + * mqprefix常量 + * mq常量 + * + * @author yezhiqiu + * @date 2021/07/28 + */ +public class MQPrefixConst { + + /** + * maxwell交换机 + */ + public static final String MAXWELL_EXCHANGE = "maxwell_exchange"; + + /** + * maxwell队列 + */ + public static final String MAXWELL_QUEUE = "maxwell_queue"; + + /** + * email交换机 + */ + public static final String EMAIL_EXCHANGE = "email_exchange"; + + /** + * 邮件队列 + */ + public static final String EMAIL_QUEUE = "email_queue"; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/constant/blog/RedisPrefixConst.java b/zhi-common/src/main/java/com/zhi/common/constant/blog/RedisPrefixConst.java new file mode 100644 index 0000000..daa3873 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/constant/blog/RedisPrefixConst.java @@ -0,0 +1,91 @@ +package com.zhi.common.constant.blog; + +/** + * redis常量 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +public class RedisPrefixConst { + + /** + * 验证码过期时间 + */ + public static final long CODE_EXPIRE_TIME = 15 * 60; + + /** + * 验证码 + */ + public static final String USER_CODE_KEY = "code:"; + + /** + * 博客浏览量 + */ + public static final String BLOG_VIEWS_COUNT = "blog_views_count"; + + /** + * 文章浏览量 + */ + public static final String ARTICLE_VIEWS_COUNT = "article_views_count"; + + /** + * 文章点赞量 + */ + public static final String ARTICLE_LIKE_COUNT = "article_like_count"; + + /** + * 用户点赞文章 + */ + public static final String ARTICLE_USER_LIKE = "article_user_like:"; + + /** + * 说说点赞量 + */ + public static final String TALK_LIKE_COUNT = "talk_like_count"; + + /** + * 用户点赞说说 + */ + public static final String TALK_USER_LIKE = "talk_user_like:"; + + /** + * 评论点赞量 + */ + public static final String COMMENT_LIKE_COUNT = "comment_like_count"; + + /** + * 用户点赞评论 + */ + public static final String COMMENT_USER_LIKE = "comment_user_like:"; + + /** + * 网站配置 + */ + public static final String WEBSITE_CONFIG = "website_config"; + + /** + * 用户地区 + */ + public static final String USER_AREA = "user_area"; + + /** + * 访客地区 + */ + public static final String VISITOR_AREA = "visitor_area"; + + /** + * 页面封面 + */ + public static final String PAGE_COVER = "page_cover"; + + /** + * 关于我信息 + */ + public static final String ABOUT = "about"; + + /** + * 访客 + */ + public static final String UNIQUE_VISITOR = "unique_visitor"; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/convert/ExcelBigNumberConvert.java b/zhi-common/src/main/java/com/zhi/common/convert/ExcelBigNumberConvert.java new file mode 100644 index 0000000..52e92af --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/convert/ExcelBigNumberConvert.java @@ -0,0 +1,52 @@ +package com.zhi.common.convert; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import lombok.extern.slf4j.Slf4j; + +import java.math.BigDecimal; + +/** + * 大数值转换 + * Excel 数值长度位15位 大于15位的数值转换位字符串 + * + * @author Lion Li + */ +@Slf4j +public class ExcelBigNumberConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Long.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return CellDataTypeEnum.STRING; + } + + @Override + public Long convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + return Convert.toLong(cellData.getData()); + } + + @Override + public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNotNull(object)) { + String str = Convert.toStr(object); + if (str.length() > 15) { + return new WriteCellData<>(str); + } + } + WriteCellData cellData = new WriteCellData<>(new BigDecimal(object)); + cellData.setType(CellDataTypeEnum.NUMBER); + return cellData; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/convert/ExcelDictConvert.java b/zhi-common/src/main/java/com/zhi/common/convert/ExcelDictConvert.java new file mode 100644 index 0000000..71c2661 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/convert/ExcelDictConvert.java @@ -0,0 +1,73 @@ +package com.zhi.common.convert; + +import cn.hutool.core.annotation.AnnotationUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.excel.converters.Converter; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.metadata.data.ReadCellData; +import com.alibaba.excel.metadata.data.WriteCellData; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.zhi.common.annotation.ExcelDictFormat; +import com.zhi.common.core.service.DictService; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; + +/** + * 字典格式化转换处理 + * + * @author Lion Li + */ +@Slf4j +public class ExcelDictConvert implements Converter { + + @Override + public Class supportJavaTypeKey() { + return Object.class; + } + + @Override + public CellDataTypeEnum supportExcelTypeKey() { + return null; + } + + @Override + public Object convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String label = cellData.getStringValue(); + String value; + if (StringUtils.isBlank(type)) { + value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator()); + } else { + value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator()); + } + return Convert.convert(contentProperty.getField().getType(), value); + } + + @Override + public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } + ExcelDictFormat anno = getAnnotation(contentProperty.getField()); + String type = anno.dictType(); + String value = Convert.toStr(object); + String label; + if (StringUtils.isBlank(type)) { + label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator()); + } else { + label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator()); + } + return new WriteCellData<>(label); + } + + private ExcelDictFormat getAnnotation(Field field) { + return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/controller/BaseController.java b/zhi-common/src/main/java/com/zhi/common/core/controller/BaseController.java new file mode 100644 index 0000000..e1acdea --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/controller/BaseController.java @@ -0,0 +1,69 @@ +package com.zhi.common.core.controller; + +import com.zhi.common.core.domain.R; +import com.zhi.common.core.domain.model.LoginUser; +import com.zhi.common.helper.LoginHelper; +import com.zhi.common.utils.StringUtils; + +/** + * web层通用数据处理 + * + * @author Lion Li + */ +public class BaseController { + + /** + * 响应返回结果 + * + * @param rows 影响行数 + * @return 操作结果 + */ + protected R toAjax(int rows) { + return rows > 0 ? R.ok() : R.fail(); + } + + /** + * 响应返回结果 + * + * @param result 结果 + * @return 操作结果 + */ + protected R toAjax(boolean result) { + return result ? R.ok() : R.fail(); + } + + /** + * 页面跳转 + */ + public String redirect(String url) { + return StringUtils.format("redirect:{}", url); + } + + /** + * 获取用户缓存信息 + */ + public LoginUser getLoginUser() { + return LoginHelper.getLoginUser(); + } + + /** + * 获取登录用户id + */ + public Long getUserId() { + return LoginHelper.getUserId(); + } + + /** + * 获取登录部门id + */ + public Long getDeptId() { + return LoginHelper.getDeptId(); + } + + /** + * 获取登录用户名 + */ + public String getUsername() { + return LoginHelper.getUsername(); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/BaseEntity.java b/zhi-common/src/main/java/com/zhi/common/core/domain/BaseEntity.java new file mode 100644 index 0000000..7ef7726 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/BaseEntity.java @@ -0,0 +1,63 @@ +package com.zhi.common.core.domain; + +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.TableField; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Entity基类 + * + * @author Lion Li + */ + +@Data +public class BaseEntity implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 搜索值 + */ + @JsonIgnore + @TableField(exist = false) + private String searchValue; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 请求参数 + */ + @JsonInclude(JsonInclude.Include.NON_EMPTY) + @TableField(exist = false) + private Map params = new HashMap<>(); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/PageQuery.java b/zhi-common/src/main/java/com/zhi/common/core/domain/PageQuery.java new file mode 100644 index 0000000..be20615 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/PageQuery.java @@ -0,0 +1,112 @@ +package com.zhi.common.core.domain; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zhi.common.exception.ServiceException; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.sql.SqlUtil; +import lombok.Data; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 分页查询实体类 + * + * @author Lion Li + */ + +@Data +public class PageQuery implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 分页大小 + */ + private Integer pageSize; + + /** + * 当前页数 + */ + private Integer pageNum; + + /** + * 排序列 + */ + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + private String isAsc; + + /** + * 当前记录起始索引 默认值 + */ + public static final int DEFAULT_PAGE_NUM = 1; + + /** + * 每页显示记录数 默认值 默认查全部 + */ + public static final int DEFAULT_PAGE_SIZE = Integer.MAX_VALUE; + + public Page build() { + Integer pageNum = ObjectUtil.defaultIfNull(getPageNum(), DEFAULT_PAGE_NUM); + Integer pageSize = ObjectUtil.defaultIfNull(getPageSize(), DEFAULT_PAGE_SIZE); + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + Page page = new Page<>(pageNum, pageSize); + List orderItems = buildOrderItem(); + if (CollUtil.isNotEmpty(orderItems)) { + page.addOrder(orderItems); + } + return page; + } + + /** + * 构建排序 + * + * 支持的用法如下: + * {isAsc:"asc",orderByColumn:"id"} order by id asc + * {isAsc:"asc",orderByColumn:"id,createTime"} order by id asc,create_time asc + * {isAsc:"desc",orderByColumn:"id,createTime"} order by id desc,create_time desc + * {isAsc:"asc,desc",orderByColumn:"id,createTime"} order by id asc,create_time desc + */ + private List buildOrderItem() { + if (StringUtils.isBlank(orderByColumn) || StringUtils.isBlank(isAsc)) { + return null; + } + String orderBy = SqlUtil.escapeOrderBySql(orderByColumn); + orderBy = StringUtils.toUnderScoreCase(orderBy); + + // 兼容前端排序类型 + isAsc = StringUtils.replaceEach(isAsc, new String[]{"ascending", "descending"}, new String[]{"asc", "desc"}); + + String[] orderByArr = orderBy.split(","); + String[] isAscArr = isAsc.split(","); + if (isAscArr.length != 1 && isAscArr.length != orderByArr.length) { + throw new ServiceException("排序参数有误"); + } + + List list = new ArrayList<>(); + // 每个字段各自排序 + for (int i = 0; i < orderByArr.length; i++) { + String orderByStr = orderByArr[i]; + String isAscStr = isAscArr.length == 1 ? isAscArr[0] : isAscArr[i]; + if ("asc".equals(isAscStr)) { + list.add(OrderItem.asc(orderByStr)); + } else if ("desc".equals(isAscStr)) { + list.add(OrderItem.desc(orderByStr)); + } else { + throw new ServiceException("排序参数有误"); + } + } + return list; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/R.java b/zhi-common/src/main/java/com/zhi/common/core/domain/R.java new file mode 100644 index 0000000..176af3f --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/R.java @@ -0,0 +1,107 @@ +package com.zhi.common.core.domain; + +import com.zhi.common.constant.HttpStatus; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 响应信息主体 + * + * @author Lion Li + */ +@Data +@NoArgsConstructor +public class R implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 成功 + */ + public static final int SUCCESS = 200; + + /** + * 失败 + */ + public static final int FAIL = 500; + + private int code; + + private String msg; + + private T data; + + public static R ok() { + return restResult(null, SUCCESS, "操作成功"); + } + + public static R ok(T data) { + return restResult(data, SUCCESS, "操作成功"); + } + + public static R ok(String msg) { + return restResult(null, SUCCESS, msg); + } + + public static R ok(String msg, T data) { + return restResult(data, SUCCESS, msg); + } + + public static R fail() { + return restResult(null, FAIL, "操作失败"); + } + + public static R fail(String msg) { + return restResult(null, FAIL, msg); + } + + public static R fail(T data) { + return restResult(data, FAIL, "操作失败"); + } + + public static R fail(String msg, T data) { + return restResult(data, FAIL, msg); + } + + public static R fail(int code, String msg) { + return restResult(null, code, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @return 警告消息 + */ + public static R warn(String msg) { + return restResult(null, HttpStatus.WARN, msg); + } + + /** + * 返回警告消息 + * + * @param msg 返回内容 + * @param data 数据对象 + * @return 警告消息 + */ + public static R warn(String msg, T data) { + return restResult(data, HttpStatus.WARN, msg); + } + + private static R restResult(T data, int code, String msg) { + R r = new R<>(); + r.setCode(code); + r.setData(data); + r.setMsg(msg); + return r; + } + + public static Boolean isError(R ret) { + return !isSuccess(ret); + } + + public static Boolean isSuccess(R ret) { + return R.SUCCESS == ret.getCode(); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/TreeEntity.java b/zhi-common/src/main/java/com/zhi/common/core/domain/TreeEntity.java new file mode 100644 index 0000000..0a91872 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/TreeEntity.java @@ -0,0 +1,39 @@ +package com.zhi.common.core.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tree基类 + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class TreeEntity extends BaseEntity { + + private static final long serialVersionUID = 1L; + + /** + * 父菜单名称 + */ + @TableField(exist = false) + private String parentName; + + /** + * 父菜单ID + */ + private Long parentId; + + /** + * 子部门 + */ + @TableField(exist = false) + private List children = new ArrayList<>(); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/dto/OperLogDTO.java b/zhi-common/src/main/java/com/zhi/common/core/domain/dto/OperLogDTO.java new file mode 100644 index 0000000..b9ea5c6 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/dto/OperLogDTO.java @@ -0,0 +1,104 @@ +package com.zhi.common.core.domain.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 通用操作日志实体 + * + * @author Lion Li + */ + +@Data +public class OperLogDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 日志主键 + */ + private Long operId; + + /** + * 操作模块 + */ + private String title; + + /** + * 业务类型(0其它 1新增 2修改 3删除) + */ + private Integer businessType; + + /** + * 业务类型数组 + */ + private Integer[] businessTypes; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求方式 + */ + private String requestMethod; + + /** + * 操作类别(0其它 1后台用户 2手机端用户) + */ + private Integer operatorType; + + /** + * 操作人员 + */ + private String operName; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 请求url + */ + private String operUrl; + + /** + * 操作地址 + */ + private String operIp; + + /** + * 操作地点 + */ + private String operLocation; + + /** + * 请求参数 + */ + private String operParam; + + /** + * 返回参数 + */ + private String jsonResult; + + /** + * 操作状态(0正常 1异常) + */ + private Integer status; + + /** + * 错误消息 + */ + private String errorMsg; + + /** + * 操作时间 + */ + private Date operTime; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/dto/RoleDTO.java b/zhi-common/src/main/java/com/zhi/common/core/domain/dto/RoleDTO.java new file mode 100644 index 0000000..1d12586 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/dto/RoleDTO.java @@ -0,0 +1,38 @@ +package com.zhi.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 角色 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class RoleDTO implements Serializable { + + /** + * 角色ID + */ + private Long roleId; + + /** + * 角色名称 + */ + private String roleName; + + /** + * 角色权限 + */ + private String roleKey; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + private String dataScope; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/dto/UserOnlineDTO.java b/zhi-common/src/main/java/com/zhi/common/core/domain/dto/UserOnlineDTO.java new file mode 100644 index 0000000..430d4a3 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/dto/UserOnlineDTO.java @@ -0,0 +1,60 @@ +package com.zhi.common.core.domain.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 当前在线会话 + * + * @author ruoyi + */ + +@Data +@NoArgsConstructor +public class UserOnlineDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 会话编号 + */ + private String tokenId; + + /** + * 部门名称 + */ + private String deptName; + + /** + * 用户名称 + */ + private String userName; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地址 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 登录时间 + */ + private Long loginTime; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDept.java b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDept.java new file mode 100644 index 0000000..d1974ec --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDept.java @@ -0,0 +1,80 @@ +package com.zhi.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.zhi.common.core.domain.TreeEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 部门表 sys_dept + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dept") +public class SysDept extends TreeEntity { + private static final long serialVersionUID = 1L; + + /** + * 部门ID + */ + @TableId(value = "dept_id") + private Long deptId; + + /** + * 部门名称 + */ + @NotBlank(message = "部门名称不能为空") + @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符") + private String deptName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 负责人 + */ + private String leader; + + /** + * 联系电话 + */ + @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符") + private String phone; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + private String email; + + /** + * 部门状态:0正常,1停用 + */ + private String status; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 祖级列表 + */ + private String ancestors; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDictData.java b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDictData.java new file mode 100644 index 0000000..803ac85 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDictData.java @@ -0,0 +1,100 @@ +package com.zhi.common.core.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.zhi.common.annotation.ExcelDictFormat; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.convert.ExcelDictConvert; +import com.zhi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +/** + * 字典数据表 sys_dict_data + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_data") +@ExcelIgnoreUnannotated +public class SysDictData extends BaseEntity { + + /** + * 字典编码 + */ + @ExcelProperty(value = "字典编码") + @TableId(value = "dict_code") + private Long dictCode; + + /** + * 字典排序 + */ + @ExcelProperty(value = "字典排序") + private Integer dictSort; + + /** + * 字典标签 + */ + @ExcelProperty(value = "字典标签") + @NotBlank(message = "字典标签不能为空") + @Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符") + private String dictLabel; + + /** + * 字典键值 + */ + @ExcelProperty(value = "字典键值") + @NotBlank(message = "字典键值不能为空") + @Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符") + private String dictValue; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符") + private String dictType; + + /** + * 样式属性(其他样式扩展) + */ + @Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符") + private String cssClass; + + /** + * 表格字典样式 + */ + private String listClass; + + /** + * 是否默认(Y是 N否) + */ + @ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + private String isDefault; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + private String remark; + + public boolean getDefault() { + return UserConstants.YES.equals(this.isDefault); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDictType.java b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDictType.java new file mode 100644 index 0000000..5cfc4e5 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysDictType.java @@ -0,0 +1,65 @@ +package com.zhi.common.core.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.zhi.common.annotation.ExcelDictFormat; +import com.zhi.common.convert.ExcelDictConvert; +import com.zhi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +/** + * 字典类型表 sys_dict_type + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_dict_type") +@ExcelIgnoreUnannotated +public class SysDictType extends BaseEntity { + + /** + * 字典主键 + */ + @ExcelProperty(value = "字典主键") + @TableId(value = "dict_id") + private Long dictId; + + /** + * 字典名称 + */ + @ExcelProperty(value = "字典名称") + @NotBlank(message = "字典名称不能为空") + @Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符") + private String dictName; + + /** + * 字典类型 + */ + @ExcelProperty(value = "字典类型") + @NotBlank(message = "字典类型不能为空") + @Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符") + @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)") + private String dictType; + + /** + * 状态(0正常 1停用) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 备注 + */ + private String remark; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysMenu.java b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysMenu.java new file mode 100644 index 0000000..518ea3c --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysMenu.java @@ -0,0 +1,104 @@ +package com.zhi.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.zhi.common.core.domain.TreeEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 菜单权限表 sys_menu + * + * @author Lion Li + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("sys_menu") +public class SysMenu extends TreeEntity { + + /** + * 菜单ID + */ + @TableId(value = "menu_id") + private Long menuId; + + /** + * 菜单名称 + */ + @NotBlank(message = "菜单名称不能为空") + @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符") + private String menuName; + + /** + * 显示顺序 + */ + @NotNull(message = "显示顺序不能为空") + private Integer orderNum; + + /** + * 路由地址 + */ + @Size(min = 0, max = 200, message = "路由地址不能超过200个字符") + private String path; + + /** + * 组件路径 + */ + @Size(min = 0, max = 200, message = "组件路径不能超过255个字符") + private String component; + + /** + * 路由参数 + */ + private String queryParam; + + /** + * 是否为外链(0是 1否) + */ + private String isFrame; + + /** + * 是否缓存(0缓存 1不缓存) + */ + private String isCache; + + /** + * 类型(M目录 C菜单 F按钮) + */ + @NotBlank(message = "菜单类型不能为空") + private String menuType; + + /** + * 显示状态(0显示 1隐藏) + */ + private String visible; + + /** + * 菜单状态(0正常 1停用) + */ + private String status; + + /** + * 权限字符串 + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") + private String perms; + + /** + * 菜单图标 + */ + private String icon; + + /** + * 备注 + */ + private String remark; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysRole.java b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysRole.java new file mode 100644 index 0000000..73c4ee4 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysRole.java @@ -0,0 +1,131 @@ +package com.zhi.common.core.domain.entity; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.zhi.common.annotation.ExcelDictFormat; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.convert.ExcelDictConvert; +import com.zhi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; + +/** + * 角色表 sys_role + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_role") +@ExcelIgnoreUnannotated +public class SysRole extends BaseEntity { + + /** + * 角色ID + */ + @ExcelProperty(value = "角色序号") + @TableId(value = "role_id") + private Long roleId; + + /** + * 角色名称 + */ + @ExcelProperty(value = "角色名称") + @NotBlank(message = "角色名称不能为空") + @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符") + private String roleName; + + /** + * 角色权限 + */ + @ExcelProperty(value = "角色权限") + @NotBlank(message = "权限字符不能为空") + @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符") + private String roleKey; + + /** + * 角色排序 + */ + @ExcelProperty(value = "角色排序") + @NotNull(message = "显示顺序不能为空") + private Integer roleSort; + + /** + * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) + */ + @ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限") + private String dataScope; + + /** + * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) + */ + private Boolean menuCheckStrictly; + + /** + * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) + */ + private Boolean deptCheckStrictly; + + /** + * 角色状态(0正常 1停用) + */ + @ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + /** + * 用户是否存在此角色标识 默认不存在 + */ + @TableField(exist = false) + private boolean flag = false; + + /** + * 菜单组 + */ + @TableField(exist = false) + private Long[] menuIds; + + /** + * 部门组(数据权限) + */ + @TableField(exist = false) + private Long[] deptIds; + + /** + * 角色菜单权限 + */ + @TableField(exist = false) + private Set permissions; + + public SysRole(Long roleId) { + this.roleId = roleId; + } + + public boolean isAdmin() { + return UserConstants.ADMIN_ID.equals(this.roleId); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysUser.java b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysUser.java new file mode 100644 index 0000000..9dbe361 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/entity/SysUser.java @@ -0,0 +1,171 @@ +package com.zhi.common.core.domain.entity; + +import com.baomidou.mybatisplus.annotation.*; +import com.zhi.common.annotation.Sensitive; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.domain.BaseEntity; +import com.zhi.common.enums.SensitiveStrategy; +import com.zhi.common.xss.Xss; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Email; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.util.Date; +import java.util.List; + +/** + * 用户对象 sys_user + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName("sys_user") +public class SysUser extends BaseEntity { + + /** + * 用户ID + */ + @TableId(value = "user_id" ,type = IdType.AUTO) + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 用户账号 + */ + @Xss(message = "用户账号不能包含脚本字符") + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") + private String userName; + + /** + * 用户昵称 + */ + @Xss(message = "用户昵称不能包含脚本字符") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") + private String nickName; + + /** + * 用户类型(sys_user系统用户) + */ + private String userType; + + /** + * 用户邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL) + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") + private String email; + + /** + * 手机号码 + */ + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String phonenumber; + + /** + * 用户性别 + */ + private String sex; + + /** + * 用户头像 + */ + private String avatar; + + /** + * 密码 + */ + @TableField( + insertStrategy = FieldStrategy.NOT_EMPTY, + updateStrategy = FieldStrategy.NOT_EMPTY, + whereStrategy = FieldStrategy.NOT_EMPTY + ) + private String password; + + /** + * 帐号状态(0正常 1停用) + */ + private String status; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 最后登录IP + */ + private String loginIp; + + /** + * 最后登录时间 + */ + private Date loginDate; + + /** + * 备注 + */ + private String remark; + + /** + * 个人简介 + */ + private String intro; + + /** + * 个人网站 + */ + private String webSite; + + /** + * 部门对象 + */ + @TableField(exist = false) + private SysDept dept; + + /** + * 角色对象 + */ + @TableField(exist = false) + private List roles; + + /** + * 角色组 + */ + @TableField(exist = false) + private Long[] roleIds; + + /** + * 岗位组 + */ + @TableField(exist = false) + private Long[] postIds; + + /** + * 数据权限 当前角色ID + */ + @TableField(exist = false) + private Long roleId; + + public SysUser(Long userId) { + this.userId = userId; + } + + public boolean isAdmin() { + return UserConstants.ADMIN_ID.equals(this.userId); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/model/BlogLoginUser.java b/zhi-common/src/main/java/com/zhi/common/core/domain/model/BlogLoginUser.java new file mode 100644 index 0000000..3eb7f91 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/model/BlogLoginUser.java @@ -0,0 +1,54 @@ +package com.zhi.common.core.domain.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author ftz-lover + * @version 1.0 + * @date 2023/1/15 13:07 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BlogLoginUser implements Serializable { + + /** + * 用户id + */ + private Long id; + + /** + * 用户头像 + */ + private String avatar; + + /** + * 用户邮件 + */ + private String email; + + /** + * 用户ip + */ + private String ipAddress; + + /** + * 用户昵称 + */ + private String nickname; + + /** + * 用户名 + */ + private String username; + + + + + + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/model/LoginBody.java b/zhi-common/src/main/java/com/zhi/common/core/domain/model/LoginBody.java new file mode 100644 index 0000000..6c3b8f5 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/model/LoginBody.java @@ -0,0 +1,42 @@ +package com.zhi.common.core.domain.model; + +import com.zhi.common.constant.UserConstants; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; + +/** + * 用户登录对象 + * + * @author Lion Li + */ + +@Data +public class LoginBody { + + /** + * 用户名 + */ + @NotBlank(message = "{user.username.not.blank}") + @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") + private String username; + + /** + * 用户密码 + */ + @NotBlank(message = "{user.password.not.blank}") + @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}") + private String password; + + /** + * 验证码 + */ + private String code; + + /** + * 唯一标识 + */ + private String uuid; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/model/LoginUser.java b/zhi-common/src/main/java/com/zhi/common/core/domain/model/LoginUser.java new file mode 100644 index 0000000..d814be4 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/model/LoginUser.java @@ -0,0 +1,117 @@ +package com.zhi.common.core.domain.model; + +import com.zhi.common.core.domain.dto.RoleDTO; +import com.zhi.common.helper.LoginHelper; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Set; + +/** + * 登录用户身份权限 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class LoginUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 用户ID + */ + private Long userId; + + /** + * 部门ID + */ + private Long deptId; + + /** + * 部门名 + */ + private String deptName; + + /** + * 用户唯一标识 + */ + private String token; + + /** + * 用户类型 + */ + private String userType; + + /** + * 登录时间 + */ + private Long loginTime; + + /** + * 过期时间 + */ + private Long expireTime; + + /** + * 登录IP地址 + */ + private String ipaddr; + + /** + * 登录地点 + */ + private String loginLocation; + + /** + * 浏览器类型 + */ + private String browser; + + /** + * 操作系统 + */ + private String os; + + /** + * 菜单权限 + */ + private Set menuPermission; + + /** + * 角色权限 + */ + private Set rolePermission; + + /** + * 用户名 + */ + private String username; + + /** + * 角色对象 + */ + private List roles; + + /** + * 数据权限 当前角色ID + */ + private Long roleId; + + /** + * 获取登录id + */ + public String getLoginId() { + if (userType == null) { + throw new IllegalArgumentException("用户类型不能为空"); + } + if (userId == null) { + throw new IllegalArgumentException("用户ID不能为空"); + } + return userType + LoginHelper.JOIN_CODE + userId; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/model/RegisterBody.java b/zhi-common/src/main/java/com/zhi/common/core/domain/model/RegisterBody.java new file mode 100644 index 0000000..c711d80 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/model/RegisterBody.java @@ -0,0 +1,17 @@ +package com.zhi.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 用户注册对象 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class RegisterBody extends LoginBody { + + private String userType; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/model/SmsLoginBody.java b/zhi-common/src/main/java/com/zhi/common/core/domain/model/SmsLoginBody.java new file mode 100644 index 0000000..1639830 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/model/SmsLoginBody.java @@ -0,0 +1,28 @@ +package com.zhi.common.core.domain.model; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 短信登录对象 + * + * @author Lion Li + */ + +@Data +public class SmsLoginBody { + + /** + * 用户名 + */ + @NotBlank(message = "{user.phonenumber.not.blank}") + private String phonenumber; + + /** + * 用户密码 + */ + @NotBlank(message = "{sms.code.not.blank}") + private String smsCode; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/domain/model/XcxLoginUser.java b/zhi-common/src/main/java/com/zhi/common/core/domain/model/XcxLoginUser.java new file mode 100644 index 0000000..09a7b86 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/domain/model/XcxLoginUser.java @@ -0,0 +1,24 @@ +package com.zhi.common.core.domain.model; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 小程序登录用户身份权限 + * + * @author Lion Li + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class XcxLoginUser extends LoginUser { + + private static final long serialVersionUID = 1L; + + /** + * openid + */ + private String openid; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/mapper/BaseMapperPlus.java b/zhi-common/src/main/java/com/zhi/common/core/mapper/BaseMapperPlus.java new file mode 100644 index 0000000..08b4245 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/mapper/BaseMapperPlus.java @@ -0,0 +1,231 @@ +package com.zhi.common.core.mapper; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.enums.SqlMethod; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.TableInfo; +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; +import com.baomidou.mybatisplus.core.toolkit.*; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; +import com.zhi.common.utils.BeanCopyUtils; +import org.apache.ibatis.binding.MapperMethod; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.logging.LogFactory; + +import java.io.Serializable; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 自定义 Mapper 接口, 实现 自定义扩展 + * + * @param mapper 泛型 + * @param table 泛型 + * @param vo 泛型 + * @author Lion Li + * @since 2021-05-13 + */ +@SuppressWarnings("unchecked") +public interface BaseMapperPlus extends BaseMapper { + + Log log = LogFactory.getLog(BaseMapperPlus.class); + + int DEFAULT_BATCH_SIZE = 1000; + + default Class currentVoClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 2); + } + + default Class currentModelClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 1); + } + + default Class currentMapperClass() { + return (Class) ReflectionKit.getSuperClassGenericType(this.getClass(), BaseMapperPlus.class, 0); + } + + default List selectList() { + return this.selectList(new QueryWrapper<>()); + } + + /** + * 批量插入 + */ + default boolean insertBatch(Collection entityList) { + return insertBatch(entityList, DEFAULT_BATCH_SIZE); + } + + /** + * 批量更新 + */ + default boolean updateBatchById(Collection entityList) { + return updateBatchById(entityList, DEFAULT_BATCH_SIZE); + } + + /** + * 批量插入或更新 + */ + default boolean insertOrUpdateBatch(Collection entityList) { + return insertOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE); + } + + /** + * 批量插入(包含限制条数) + */ + default boolean insertBatch(Collection entityList, int batchSize) { + String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.INSERT_ONE); + return SqlHelper.executeBatch(this.currentModelClass(), log, entityList, batchSize, + (sqlSession, entity) -> sqlSession.insert(sqlStatement, entity)); + } + + /** + * 批量更新(包含限制条数) + */ + default boolean updateBatchById(Collection entityList, int batchSize) { + String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.UPDATE_BY_ID); + return SqlHelper.executeBatch(this.currentModelClass(), log, entityList, batchSize, + (sqlSession, entity) -> { + MapperMethod.ParamMap param = new MapperMethod.ParamMap<>(); + param.put(Constants.ENTITY, entity); + sqlSession.update(sqlStatement, param); + }); + } + + /** + * 批量插入或更新(包含限制条数) + */ + default boolean insertOrUpdateBatch(Collection entityList, int batchSize) { + TableInfo tableInfo = TableInfoHelper.getTableInfo(this.currentModelClass()); + Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); + String keyProperty = tableInfo.getKeyProperty(); + Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); + return SqlHelper.saveOrUpdateBatch(this.currentModelClass(), this.currentMapperClass(), log, entityList, batchSize, (sqlSession, entity) -> { + Object idVal = tableInfo.getPropertyValue(entity, keyProperty); + String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.SELECT_BY_ID); + return StringUtils.checkValNull(idVal) + || CollectionUtils.isEmpty(sqlSession.selectList(sqlStatement, entity)); + }, (sqlSession, entity) -> { + MapperMethod.ParamMap param = new MapperMethod.ParamMap<>(); + param.put(Constants.ENTITY, entity); + String sqlStatement = SqlHelper.getSqlStatement(this.currentMapperClass(), SqlMethod.UPDATE_BY_ID); + sqlSession.update(sqlStatement, param); + }); + } + + /** + * 插入或更新(包含限制条数) + */ + default boolean insertOrUpdate(T entity) { + if (null != entity) { + TableInfo tableInfo = TableInfoHelper.getTableInfo(this.currentModelClass()); + Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); + String keyProperty = tableInfo.getKeyProperty(); + Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); + Object idVal = tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty()); + return StringUtils.checkValNull(idVal) || Objects.isNull(selectById((Serializable) idVal)) ? insert(entity) > 0 : updateById(entity) > 0; + } + return false; + } + + default V selectVoById(Serializable id) { + return selectVoById(id, this.currentVoClass()); + } + + /** + * 根据 ID 查询 + */ + default C selectVoById(Serializable id, Class voClass) { + T obj = this.selectById(id); + if (ObjectUtil.isNull(obj)) { + return null; + } + return BeanCopyUtils.copy(obj, voClass); + } + + default List selectVoBatchIds(Collection idList) { + return selectVoBatchIds(idList, this.currentVoClass()); + } + + /** + * 查询(根据ID 批量查询) + */ + default List selectVoBatchIds(Collection idList, Class voClass) { + List list = this.selectBatchIds(idList); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return BeanCopyUtils.copyList(list, voClass); + } + + default List selectVoByMap(Map map) { + return selectVoByMap(map, this.currentVoClass()); + } + + /** + * 查询(根据 columnMap 条件) + */ + default List selectVoByMap(Map map, Class voClass) { + List list = this.selectByMap(map); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return BeanCopyUtils.copyList(list, voClass); + } + + default V selectVoOne(Wrapper wrapper) { + return selectVoOne(wrapper, this.currentVoClass()); + } + + /** + * 根据 entity 条件,查询一条记录 + */ + default C selectVoOne(Wrapper wrapper, Class voClass) { + T obj = this.selectOne(wrapper); + if (ObjectUtil.isNull(obj)) { + return null; + } + return BeanCopyUtils.copy(obj, voClass); + } + + default List selectVoList(Wrapper wrapper) { + return selectVoList(wrapper, this.currentVoClass()); + } + + /** + * 根据 entity 条件,查询全部记录 + */ + default List selectVoList(Wrapper wrapper, Class voClass) { + List list = this.selectList(wrapper); + if (CollUtil.isEmpty(list)) { + return CollUtil.newArrayList(); + } + return BeanCopyUtils.copyList(list, voClass); + } + + default

> P selectVoPage(IPage page, Wrapper wrapper) { + + return selectVoPage(page, wrapper, this.currentVoClass()); + } + + /** + * 分页查询VO + */ + default > P selectVoPage(IPage page, Wrapper wrapper, Class voClass) { + IPage pageData = this.selectPage(page, wrapper); + IPage voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal()); + + if (CollUtil.isEmpty(pageData.getRecords())) { + return (P) voPage; + } + voPage.setRecords(BeanCopyUtils.copyList(pageData.getRecords(), voClass)); + return (P) voPage; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/page/TableDataInfo.java b/zhi-common/src/main/java/com/zhi/common/core/page/TableDataInfo.java new file mode 100644 index 0000000..88e282b --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/page/TableDataInfo.java @@ -0,0 +1,78 @@ +package com.zhi.common.core.page; + +import cn.hutool.http.HttpStatus; +import com.baomidou.mybatisplus.core.metadata.IPage; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 表格分页数据对象 + * + * @author Lion Li + */ + +@Data +@NoArgsConstructor +public class TableDataInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 总记录数 + */ + private long total; + + /** + * 列表数据 + */ + private List rows; + + /** + * 消息状态码 + */ + private int code; + + /** + * 消息内容 + */ + private String msg; + + /** + * 分页 + * + * @param list 列表数据 + * @param total 总记录数 + */ + public TableDataInfo(List list, long total) { + this.rows = list; + this.total = total; + } + + public static TableDataInfo build(IPage page) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(page.getRecords()); + rspData.setTotal(page.getTotal()); + return rspData; + } + + public static TableDataInfo build(List list) { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + rspData.setRows(list); + rspData.setTotal(list.size()); + return rspData; + } + + public static TableDataInfo build() { + TableDataInfo rspData = new TableDataInfo<>(); + rspData.setCode(HttpStatus.HTTP_OK); + rspData.setMsg("查询成功"); + return rspData; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/ConfigService.java b/zhi-common/src/main/java/com/zhi/common/core/service/ConfigService.java new file mode 100644 index 0000000..dca2177 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/ConfigService.java @@ -0,0 +1,18 @@ +package com.zhi.common.core.service; + +/** + * 通用 参数配置服务 + * + * @author Lion Li + */ +public interface ConfigService { + + /** + * 根据参数 key 获取参数值 + * + * @param configKey 参数 key + * @return 参数值 + */ + String getConfigValue(String configKey); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/DeptService.java b/zhi-common/src/main/java/com/zhi/common/core/service/DeptService.java new file mode 100644 index 0000000..97dd8ef --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/DeptService.java @@ -0,0 +1,18 @@ +package com.zhi.common.core.service; + +/** + * 通用 部门服务 + * + * @author Lion Li + */ +public interface DeptService { + + /** + * 通过部门ID查询部门名称 + * + * @param deptIds 部门ID串逗号分隔 + * @return 部门名称串逗号分隔 + */ + String selectDeptNameByIds(String deptIds); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/DictService.java b/zhi-common/src/main/java/com/zhi/common/core/service/DictService.java new file mode 100644 index 0000000..66c3e19 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/DictService.java @@ -0,0 +1,57 @@ +package com.zhi.common.core.service; + +/** + * 通用 字典服务 + * + * @author Lion Li + */ +public interface DictService { + + /** + * 分隔符 + */ + String SEPARATOR = ","; + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + default String getDictLabel(String dictType, String dictValue) { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + default String getDictValue(String dictType, String dictLabel) { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + String getDictLabel(String dictType, String dictValue, String separator); + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + String getDictValue(String dictType, String dictLabel, String separator); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/LogininforService.java b/zhi-common/src/main/java/com/zhi/common/core/service/LogininforService.java new file mode 100644 index 0000000..dca81d0 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/LogininforService.java @@ -0,0 +1,14 @@ +package com.zhi.common.core.service; + +import javax.servlet.http.HttpServletRequest; + +/** + * 通用 系统访问日志 + * + * @author Lion Li + */ +public interface LogininforService { + + void recordLogininfor(String username, String status, String message, + HttpServletRequest request, Object... args); +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/OperLogService.java b/zhi-common/src/main/java/com/zhi/common/core/service/OperLogService.java new file mode 100644 index 0000000..4287e01 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/OperLogService.java @@ -0,0 +1,15 @@ +package com.zhi.common.core.service; + +import com.zhi.common.core.domain.dto.OperLogDTO; +import org.springframework.scheduling.annotation.Async; + +/** + * 通用 操作日志 + * + * @author Lion Li + */ +public interface OperLogService { + + @Async + void recordOper(OperLogDTO operLogDTO); +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/OssService.java b/zhi-common/src/main/java/com/zhi/common/core/service/OssService.java new file mode 100644 index 0000000..f530dac --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/OssService.java @@ -0,0 +1,18 @@ +package com.zhi.common.core.service; + +/** + * 通用 OSS服务 + * + * @author Lion Li + */ +public interface OssService { + + /** + * 通过ossId查询对应的url + * + * @param ossIds ossId串逗号分隔 + * @return url串逗号分隔 + */ + String selectUrlByIds(String ossIds); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/SensitiveService.java b/zhi-common/src/main/java/com/zhi/common/core/service/SensitiveService.java new file mode 100644 index 0000000..dae67b3 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/SensitiveService.java @@ -0,0 +1,18 @@ +package com.zhi.common.core.service; + +/** + * 脱敏服务 + * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author Lion Li + * @version 3.6.0 + */ +public interface SensitiveService { + + /** + * 是否脱敏 + */ + boolean isSensitive(); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/service/UserService.java b/zhi-common/src/main/java/com/zhi/common/core/service/UserService.java new file mode 100644 index 0000000..a880287 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/service/UserService.java @@ -0,0 +1,18 @@ +package com.zhi.common.core.service; + +/** + * 通用 用户服务 + * + * @author Lion Li + */ +public interface UserService { + + /** + * 通过用户ID查询用户账户 + * + * @param userId 用户ID + * @return 用户账户 + */ + String selectUserNameById(Long userId); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/validate/AddGroup.java b/zhi-common/src/main/java/com/zhi/common/core/validate/AddGroup.java new file mode 100644 index 0000000..ef99802 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/validate/AddGroup.java @@ -0,0 +1,9 @@ +package com.zhi.common.core.validate; + +/** + * 校验分组 add + * + * @author Lion Li + */ +public interface AddGroup { +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/validate/EditGroup.java b/zhi-common/src/main/java/com/zhi/common/core/validate/EditGroup.java new file mode 100644 index 0000000..5ca586d --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/validate/EditGroup.java @@ -0,0 +1,9 @@ +package com.zhi.common.core.validate; + +/** + * 校验分组 edit + * + * @author Lion Li + */ +public interface EditGroup { +} diff --git a/zhi-common/src/main/java/com/zhi/common/core/validate/QueryGroup.java b/zhi-common/src/main/java/com/zhi/common/core/validate/QueryGroup.java new file mode 100644 index 0000000..2007f21 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/core/validate/QueryGroup.java @@ -0,0 +1,9 @@ +package com.zhi.common.core.validate; + +/** + * 校验分组 query + * + * @author Lion Li + */ +public interface QueryGroup { +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/BusinessStatus.java b/zhi-common/src/main/java/com/zhi/common/enums/BusinessStatus.java new file mode 100644 index 0000000..6c12d82 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/BusinessStatus.java @@ -0,0 +1,18 @@ +package com.zhi.common.enums; + +/** + * 操作状态 + * + * @author ruoyi + */ +public enum BusinessStatus { + /** + * 成功 + */ + SUCCESS, + + /** + * 失败 + */ + FAIL, +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/BusinessType.java b/zhi-common/src/main/java/com/zhi/common/enums/BusinessType.java new file mode 100644 index 0000000..9d33d1d --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/BusinessType.java @@ -0,0 +1,58 @@ +package com.zhi.common.enums; + +/** + * 业务操作类型 + * + * @author ruoyi + */ +public enum BusinessType { + /** + * 其它 + */ + OTHER, + + /** + * 新增 + */ + INSERT, + + /** + * 修改 + */ + UPDATE, + + /** + * 删除 + */ + DELETE, + + /** + * 授权 + */ + GRANT, + + /** + * 导出 + */ + EXPORT, + + /** + * 导入 + */ + IMPORT, + + /** + * 强退 + */ + FORCE, + + /** + * 生成代码 + */ + GENCODE, + + /** + * 清空数据 + */ + CLEAN, +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/CaptchaCategory.java b/zhi-common/src/main/java/com/zhi/common/enums/CaptchaCategory.java new file mode 100644 index 0000000..806d044 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/CaptchaCategory.java @@ -0,0 +1,35 @@ +package com.zhi.common.enums; + +import cn.hutool.captcha.AbstractCaptcha; +import cn.hutool.captcha.CircleCaptcha; +import cn.hutool.captcha.LineCaptcha; +import cn.hutool.captcha.ShearCaptcha; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类别 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum CaptchaCategory { + + /** + * 线段干扰 + */ + LINE(LineCaptcha.class), + + /** + * 圆圈干扰 + */ + CIRCLE(CircleCaptcha.class), + + /** + * 扭曲干扰 + */ + SHEAR(ShearCaptcha.class); + + private final Class clazz; +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/CaptchaType.java b/zhi-common/src/main/java/com/zhi/common/enums/CaptchaType.java new file mode 100644 index 0000000..150ef27 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/CaptchaType.java @@ -0,0 +1,29 @@ +package com.zhi.common.enums; + +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.captcha.generator.RandomGenerator; +import com.zhi.common.captcha.UnsignedMathGenerator; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 验证码类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum CaptchaType { + + /** + * 数字 + */ + MATH(UnsignedMathGenerator.class), + + /** + * 字符 + */ + CHAR(RandomGenerator.class); + + private final Class clazz; +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/DataBaseType.java b/zhi-common/src/main/java/com/zhi/common/enums/DataBaseType.java new file mode 100644 index 0000000..832bedb --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/DataBaseType.java @@ -0,0 +1,49 @@ +package com.zhi.common.enums; + +import com.zhi.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据库类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DataBaseType { + + /** + * MySQL + */ + MY_SQL("MySQL"), + + /** + * Oracle + */ + ORACLE("Oracle"), + + /** + * PostgreSQL + */ + POSTGRE_SQL("PostgreSQL"), + + /** + * SQL Server + */ + SQL_SERVER("Microsoft SQL Server"); + + private final String type; + + public static DataBaseType find(String databaseProductName) { + if (StringUtils.isBlank(databaseProductName)) { + return null; + } + for (DataBaseType type : values()) { + if (type.getType().equals(databaseProductName)) { + return type; + } + } + return null; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/DataScopeType.java b/zhi-common/src/main/java/com/zhi/common/enums/DataScopeType.java new file mode 100644 index 0000000..6192dec --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/DataScopeType.java @@ -0,0 +1,72 @@ +package com.zhi.common.enums; + +import com.zhi.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 数据权限类型 + *

+ * 语法支持 spel 模板表达式 + *

+ * 内置数据 user 当前用户 内容参考 LoginUser + * 如需扩展数据 可使用 {@link com.zhi.common.helper.DataPermissionHelper} 操作 + * 内置服务 sdss 系统数据权限服务 内容参考 SysDataScopeService + * 如需扩展更多自定义服务 可以参考 sdss 自行编写 + * + * @author Lion Li + * @version 3.5.0 + */ +@Getter +@AllArgsConstructor +public enum DataScopeType { + + /** + * 全部数据权限 + */ + ALL("1", "", ""), + + /** + * 自定数据权限 + */ + CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""), + + /** + * 部门数据权限 + */ + DEPT("3", " #{#deptName} = #{#user.deptId} ", ""), + + /** + * 部门及以下数据权限 + */ + DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""), + + /** + * 仅本人数据权限 + */ + SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 "); + + private final String code; + + /** + * 语法 采用 spel 模板表达式 + */ + private final String sqlTemplate; + + /** + * 不满足 sqlTemplate 则填充 + */ + private final String elseSql; + + public static DataScopeType findCode(String code) { + if (StringUtils.isBlank(code)) { + return null; + } + for (DataScopeType type : values()) { + if (type.getCode().equals(code)) { + return type; + } + } + return null; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/DeviceType.java b/zhi-common/src/main/java/com/zhi/common/enums/DeviceType.java new file mode 100644 index 0000000..26f4476 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/DeviceType.java @@ -0,0 +1,32 @@ +package com.zhi.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对一套 用户体系 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum DeviceType { + + /** + * pc端 + */ + PC("pc"), + + /** + * app端 + */ + APP("app"), + + /** + * 小程序端 + */ + XCX("xcx"); + + private final String device; +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/HttpMethod.java b/zhi-common/src/main/java/com/zhi/common/enums/HttpMethod.java new file mode 100644 index 0000000..7437f8a --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/HttpMethod.java @@ -0,0 +1,32 @@ +package com.zhi.common.enums; + +import org.springframework.lang.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * 请求方式 + * + * @author ruoyi + */ +public enum HttpMethod { + GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE; + + private static final Map mappings = new HashMap<>(16); + + static { + for (HttpMethod httpMethod : values()) { + mappings.put(httpMethod.name(), httpMethod); + } + } + + @Nullable + public static HttpMethod resolve(@Nullable String method) { + return (method != null ? mappings.get(method) : null); + } + + public boolean matches(String method) { + return (this == resolve(method)); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/LimitType.java b/zhi-common/src/main/java/com/zhi/common/enums/LimitType.java new file mode 100644 index 0000000..be91a6e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/LimitType.java @@ -0,0 +1,24 @@ +package com.zhi.common.enums; + +/** + * 限流类型 + * + * @author ruoyi + */ + +public enum LimitType { + /** + * 默认策略全局限流 + */ + DEFAULT, + + /** + * 根据请求者IP进行限流 + */ + IP, + + /** + * 实例限流(集群多后端实例) + */ + CLUSTER +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/LoginType.java b/zhi-common/src/main/java/com/zhi/common/enums/LoginType.java new file mode 100644 index 0000000..abb3303 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/LoginType.java @@ -0,0 +1,39 @@ +package com.zhi.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 登录类型 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum LoginType { + + /** + * 密码登录 + */ + PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"), + + /** + * 短信登录 + */ + SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"), + + /** + * 小程序登录 + */ + XCX("", ""); + + /** + * 登录重试超出限制提示 + */ + final String retryLimitExceed; + + /** + * 登录重试限制计数提示 + */ + final String retryLimitCount; +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/OperatorType.java b/zhi-common/src/main/java/com/zhi/common/enums/OperatorType.java new file mode 100644 index 0000000..854df06 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/OperatorType.java @@ -0,0 +1,23 @@ +package com.zhi.common.enums; + +/** + * 操作人类别 + * + * @author ruoyi + */ +public enum OperatorType { + /** + * 其它 + */ + OTHER, + + /** + * 后台用户 + */ + MANAGE, + + /** + * 手机端用户 + */ + MOBILE +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/SensitiveStrategy.java b/zhi-common/src/main/java/com/zhi/common/enums/SensitiveStrategy.java new file mode 100644 index 0000000..bb92083 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/SensitiveStrategy.java @@ -0,0 +1,49 @@ +package com.zhi.common.enums; + +import cn.hutool.core.util.DesensitizedUtil; +import lombok.AllArgsConstructor; + +import java.util.function.Function; + +/** + * 脱敏策略 + * + * @author Yjoioooo + * @version 3.6.0 + */ +@AllArgsConstructor +public enum SensitiveStrategy { + + /** + * 身份证脱敏 + */ + ID_CARD(s -> DesensitizedUtil.idCardNum(s, 3, 4)), + + /** + * 手机号脱敏 + */ + PHONE(DesensitizedUtil::mobilePhone), + + /** + * 地址脱敏 + */ + ADDRESS(s -> DesensitizedUtil.address(s, 8)), + + /** + * 邮箱脱敏 + */ + EMAIL(DesensitizedUtil::email), + + /** + * 银行卡 + */ + BANK_CARD(DesensitizedUtil::bankCard); + + //可自行添加其他脱敏策略 + + private final Function desensitizer; + + public Function desensitizer() { + return desensitizer; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/UserStatus.java b/zhi-common/src/main/java/com/zhi/common/enums/UserStatus.java new file mode 100644 index 0000000..748ff85 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/UserStatus.java @@ -0,0 +1,26 @@ +package com.zhi.common.enums; + +/** + * 用户状态 + * + * @author ruoyi + */ +public enum UserStatus { + OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除"); + + private final String code; + private final String info; + + UserStatus(String code, String info) { + this.code = code; + this.info = info; + } + + public String getCode() { + return code; + } + + public String getInfo() { + return info; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/UserType.java b/zhi-common/src/main/java/com/zhi/common/enums/UserType.java new file mode 100644 index 0000000..96f7a37 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/UserType.java @@ -0,0 +1,37 @@ +package com.zhi.common.enums; + +import com.zhi.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 设备类型 + * 针对多套 用户体系 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum UserType { + + /** + * pc端 + */ + SYS_USER("sys_user"), + + /** + * app端 + */ + APP_USER("app_user"); + + private final String userType; + + public static UserType getUserType(String str) { + for (UserType value : values()) { + if (StringUtils.contains(str, value.getUserType())) { + return value; + } + } + throw new RuntimeException("'UserType' not found By " + str); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/blog/ArticleStatusEnum.java b/zhi-common/src/main/java/com/zhi/common/enums/blog/ArticleStatusEnum.java new file mode 100644 index 0000000..c281d62 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/blog/ArticleStatusEnum.java @@ -0,0 +1,38 @@ +package com.zhi.common.enums.blog; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 文章状态枚举 + * + * @author yezhiqiu + * @date 2021/08/10 + */ +@Getter +@AllArgsConstructor +public enum ArticleStatusEnum { + /** + * 公开 + */ + PUBLIC(1, "公开"), + /** + * 私密 + */ + SECRET(2, "私密"), + /** + * 草稿 + */ + DRAFT(3, "草稿"); + + /** + * 状态 + */ + private final Integer status; + + /** + * 描述 + */ + private final String desc; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/blog/ChatTypeEnum.java b/zhi-common/src/main/java/com/zhi/common/enums/blog/ChatTypeEnum.java new file mode 100644 index 0000000..ed459c9 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/blog/ChatTypeEnum.java @@ -0,0 +1,64 @@ +package com.zhi.common.enums.blog; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 聊天类型枚举 + * + * @author yezhiqiu + * @date 2021/08/06 + */ +@Getter +@AllArgsConstructor +public enum ChatTypeEnum { + /** + * 在线人数 + */ + ONLINE_COUNT(1, "在线人数"), + /** + * 历史记录 + */ + HISTORY_RECORD(2, "历史记录"), + /** + * 发送消息 + */ + SEND_MESSAGE(3, "发送消息"), + /** + * 撤回消息 + */ + RECALL_MESSAGE(4, "撤回消息"), + /** + * 语音消息 + */ + VOICE_MESSAGE(5,"语音消息"), + /** + * 心跳消息 + */ + HEART_BEAT(6,"心跳消息"); + + /** + * 类型 + */ + private final Integer type; + + /** + * 描述 + */ + private final String desc; + + /** + * 根据类型获取枚举 + * @param type 类型 + * @return 枚举 + */ + public static ChatTypeEnum getChatType(Integer type) { + for (ChatTypeEnum chatType : ChatTypeEnum.values()) { + if (chatType.getType().equals(type)) { + return chatType; + } + } + return null; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/enums/blog/SearchModeEnum.java b/zhi-common/src/main/java/com/zhi/common/enums/blog/SearchModeEnum.java new file mode 100644 index 0000000..524b082 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/enums/blog/SearchModeEnum.java @@ -0,0 +1,49 @@ +package com.zhi.common.enums.blog; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 搜索类型枚举 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +@Getter +@AllArgsConstructor +public enum SearchModeEnum { + /** + * mysql + */ + MYSQL("mysql", "mySqlSearchStrategyImpl"), + /** + * elasticsearch + */ + ELASTICSEARCH("elasticsearch", "esSearchStrategyImpl"); + + /** + * 模式 + */ + private final String mode; + + /** + * 策略 + */ + private final String strategy; + + /** + * 获取策略 + * + * @param mode 模式 + * @return {@link String} 搜索策略 + */ + public static String getStrategy(String mode) { + for (SearchModeEnum value : SearchModeEnum.values()) { + if (value.getMode().equals(mode)) { + return value.getStrategy(); + } + } + return null; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/excel/CellMergeStrategy.java b/zhi-common/src/main/java/com/zhi/common/excel/CellMergeStrategy.java new file mode 100644 index 0000000..b19d56a --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/excel/CellMergeStrategy.java @@ -0,0 +1,114 @@ +package com.zhi.common.excel; + +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import com.zhi.common.annotation.CellMerge; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 列值重复合并策略 + * + * @author Lion Li + */ +@AllArgsConstructor +@Slf4j +public class CellMergeStrategy extends AbstractMergeStrategy { + + private List list; + private boolean hasTitle; + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + List cellList = handle(list, hasTitle); + // judge the list is not null + if (CollectionUtils.isNotEmpty(cellList)) { + // the judge is necessary + if (cell.getRowIndex() == 1 && cell.getColumnIndex() == 0) { + for (CellRangeAddress item : cellList) { + sheet.addMergedRegion(item); + } + } + } + } + + @SneakyThrows + private static List handle(List list, boolean hasTitle) { + List cellList = new ArrayList<>(); + if (CollectionUtils.isEmpty(list)) { + return cellList; + } + Class clazz = list.get(0).getClass(); + Field[] fields = clazz.getDeclaredFields(); + // 有注解的字段 + List mergeFields = new ArrayList<>(); + List mergeFieldsIndex = new ArrayList<>(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (field.isAnnotationPresent(CellMerge.class)) { + CellMerge cm = field.getAnnotation(CellMerge.class); + mergeFields.add(field); + mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index()); + } + } + // 行合并开始下标 + int rowIndex = hasTitle ? 1 : 0; + Map map = new HashMap<>(); + // 生成两两合并单元格 + for (int i = 0; i < list.size(); i++) { + for (int j = 0; j < mergeFields.size(); j++) { + Field field = mergeFields.get(j); + String name = field.getName(); + String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); + Method readMethod = clazz.getMethod(methodName); + Object val = readMethod.invoke(list.get(i)); + + int colNum = mergeFieldsIndex.get(j); + if (!map.containsKey(field)) { + map.put(field, new RepeatCell(val, i)); + } else { + RepeatCell repeatCell = map.get(field); + Object cellValue = repeatCell.getValue(); + if (cellValue == null || "".equals(cellValue)) { + // 空值跳过不合并 + continue; + } + if (cellValue != val) { + if (i - repeatCell.getCurrent() > 1) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum)); + } + map.put(field, new RepeatCell(val, i)); + } else if (i == list.size() - 1) { + if (i > repeatCell.getCurrent()) { + cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum)); + } + } + } + } + } + return cellList; + } + + @Data + @AllArgsConstructor + static class RepeatCell { + + private Object value; + + private int current; + + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/excel/DefaultExcelListener.java b/zhi-common/src/main/java/com/zhi/common/excel/DefaultExcelListener.java new file mode 100644 index 0000000..d933e30 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/excel/DefaultExcelListener.java @@ -0,0 +1,106 @@ +package com.zhi.common.excel; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.zhi.common.utils.JsonUtils; +import com.zhi.common.utils.StreamUtils; +import com.zhi.common.utils.ValidatorUtils; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import java.util.Map; +import java.util.Set; + +/** + * Excel 导入监听 + * + * @author Yjoioooo + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor +public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener { + + /** + * 是否Validator检验,默认为是 + */ + private Boolean isValidate = Boolean.TRUE; + + /** + * excel 表头数据 + */ + private Map headMap; + + /** + * 导入回执 + */ + private ExcelResult excelResult; + + public DefaultExcelListener(boolean isValidate) { + this.excelResult = new DefautExcelResult<>(); + this.isValidate = isValidate; + } + + /** + * 处理异常 + * + * @param exception ExcelDataConvertException + * @param context Excel 上下文 + */ + @Override + public void onException(Exception exception, AnalysisContext context) throws Exception { + String errMsg = null; + if (exception instanceof ExcelDataConvertException) { + // 如果是某一个单元格的转换异常 能获取到具体行号 + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + Integer rowIndex = excelDataConvertException.getRowIndex(); + Integer columnIndex = excelDataConvertException.getColumnIndex(); + errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", + rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + if (exception instanceof ConstraintViolationException) { + ConstraintViolationException constraintViolationException = (ConstraintViolationException) exception; + Set> constraintViolations = constraintViolationException.getConstraintViolations(); + String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); + errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); + if (log.isDebugEnabled()) { + log.error(errMsg); + } + } + excelResult.getErrorList().add(errMsg); + throw new ExcelAnalysisException(errMsg); + } + + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + this.headMap = headMap; + log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap)); + } + + @Override + public void invoke(T data, AnalysisContext context) { + if (isValidate) { + ValidatorUtils.validate(data); + } + excelResult.getList().add(data); + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.debug("所有数据解析完成!"); + } + + @Override + public ExcelResult getExcelResult() { + return excelResult; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/excel/DefautExcelResult.java b/zhi-common/src/main/java/com/zhi/common/excel/DefautExcelResult.java new file mode 100644 index 0000000..735310f --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/excel/DefautExcelResult.java @@ -0,0 +1,73 @@ +package com.zhi.common.excel; + +import cn.hutool.core.util.StrUtil; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +/** + * 默认excel返回对象 + * + * @author Yjoioooo + * @author Lion Li + */ +public class DefautExcelResult implements ExcelResult { + + /** + * 数据对象list + */ + @Setter + private List list; + + /** + * 错误信息列表 + */ + @Setter + private List errorList; + + public DefautExcelResult() { + this.list = new ArrayList<>(); + this.errorList = new ArrayList<>(); + } + + public DefautExcelResult(List list, List errorList) { + this.list = list; + this.errorList = errorList; + } + + public DefautExcelResult(ExcelResult excelResult) { + this.list = excelResult.getList(); + this.errorList = excelResult.getErrorList(); + } + + @Override + public List getList() { + return list; + } + + @Override + public List getErrorList() { + return errorList; + } + + /** + * 获取导入回执 + * + * @return 导入回执 + */ + @Override + public String getAnalysis() { + int successCount = list.size(); + int errorCount = errorList.size(); + if (successCount == 0) { + return "读取失败,未解析到数据"; + } else { + if (errorCount == 0) { + return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); + } else { + return ""; + } + } + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/excel/ExcelListener.java b/zhi-common/src/main/java/com/zhi/common/excel/ExcelListener.java new file mode 100644 index 0000000..8f0a999 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/excel/ExcelListener.java @@ -0,0 +1,14 @@ +package com.zhi.common.excel; + +import com.alibaba.excel.read.listener.ReadListener; + +/** + * Excel 导入监听 + * + * @author Lion Li + */ +public interface ExcelListener extends ReadListener { + + ExcelResult getExcelResult(); + +} diff --git a/zhi-common/src/main/java/com/zhi/common/excel/ExcelResult.java b/zhi-common/src/main/java/com/zhi/common/excel/ExcelResult.java new file mode 100644 index 0000000..30cb0bb --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/excel/ExcelResult.java @@ -0,0 +1,26 @@ +package com.zhi.common.excel; + +import java.util.List; + +/** + * excel返回对象 + * + * @author Lion Li + */ +public interface ExcelResult { + + /** + * 对象列表 + */ + List getList(); + + /** + * 错误列表 + */ + List getErrorList(); + + /** + * 导入回执 + */ + String getAnalysis(); +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/DemoModeException.java b/zhi-common/src/main/java/com/zhi/common/exception/DemoModeException.java new file mode 100644 index 0000000..ca54024 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/DemoModeException.java @@ -0,0 +1,13 @@ +package com.zhi.common.exception; + +/** + * 演示模式异常 + * + * @author ruoyi + */ +public class DemoModeException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public DemoModeException() { + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/GlobalException.java b/zhi-common/src/main/java/com/zhi/common/exception/GlobalException.java new file mode 100644 index 0000000..4a98849 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/GlobalException.java @@ -0,0 +1,52 @@ +package com.zhi.common.exception; + +/** + * 全局异常 + * + * @author ruoyi + */ +public class GlobalException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + *

+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public GlobalException() { + } + + public GlobalException(String message) { + this.message = message; + } + + public String getDetailMessage() { + return detailMessage; + } + + public GlobalException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } + + @Override + public String getMessage() { + return message; + } + + public GlobalException setMessage(String message) { + this.message = message; + return this; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/ServiceException.java b/zhi-common/src/main/java/com/zhi/common/exception/ServiceException.java new file mode 100644 index 0000000..1a37e29 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/ServiceException.java @@ -0,0 +1,65 @@ +package com.zhi.common.exception; + +/** + * 业务异常 + * + * @author ruoyi + */ +public final class ServiceException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误提示 + */ + private String message; + + /** + * 错误明细,内部调试错误 + *

+ * 和 {@link CommonResult#getDetailMessage()} 一致的设计 + */ + private String detailMessage; + + /** + * 空构造方法,避免反序列化问题 + */ + public ServiceException() { + } + + public ServiceException(String message) { + this.message = message; + } + + public ServiceException(String message, Integer code) { + this.message = message; + this.code = code; + } + + public String getDetailMessage() { + return detailMessage; + } + + @Override + public String getMessage() { + return message; + } + + public Integer getCode() { + return code; + } + + public ServiceException setMessage(String message) { + this.message = message; + return this; + } + + public ServiceException setDetailMessage(String detailMessage) { + this.detailMessage = detailMessage; + return this; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/UtilException.java b/zhi-common/src/main/java/com/zhi/common/exception/UtilException.java new file mode 100644 index 0000000..94f553d --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/UtilException.java @@ -0,0 +1,22 @@ +package com.zhi.common.exception; + +/** + * 工具类异常 + * + * @author ruoyi + */ +public class UtilException extends RuntimeException { + private static final long serialVersionUID = 8247610319171014183L; + + public UtilException(Throwable e) { + super(e.getMessage(), e); + } + + public UtilException(String message) { + super(message); + } + + public UtilException(String message, Throwable throwable) { + super(message, throwable); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/base/BaseException.java b/zhi-common/src/main/java/com/zhi/common/exception/base/BaseException.java new file mode 100644 index 0000000..6ea8a4e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/base/BaseException.java @@ -0,0 +1,75 @@ +package com.zhi.common.exception.base; + +import com.zhi.common.utils.MessageUtils; +import com.zhi.common.utils.StringUtils; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +/** + * 基础异常 + * + * @author ruoyi + */ +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +public class BaseException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * 所属模块 + */ + private String module; + + /** + * 错误码 + */ + private String code; + + /** + * 错误码对应的参数 + */ + private Object[] args; + + /** + * 错误消息 + */ + private String defaultMessage; + + public BaseException(String module, String code, Object[] args, String defaultMessage) { + this.module = module; + this.code = code; + this.args = args; + this.defaultMessage = defaultMessage; + } + + public BaseException(String module, String code, Object[] args) { + this(module, code, args, null); + } + + public BaseException(String module, String defaultMessage) { + this(module, null, null, defaultMessage); + } + + public BaseException(String code, Object[] args) { + this(null, code, args, null); + } + + public BaseException(String defaultMessage) { + this(null, null, null, defaultMessage); + } + + @Override + public String getMessage() { + String message = null; + if (!StringUtils.isEmpty(code)) { + message = MessageUtils.message(code, args); + } + if (message == null) { + message = defaultMessage; + } + return message; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/file/FileException.java b/zhi-common/src/main/java/com/zhi/common/exception/file/FileException.java new file mode 100644 index 0000000..6dd2375 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/file/FileException.java @@ -0,0 +1,17 @@ +package com.zhi.common.exception.file; + +import com.zhi.common.exception.base.BaseException; + +/** + * 文件信息异常类 + * + * @author ruoyi + */ +public class FileException extends BaseException { + private static final long serialVersionUID = 1L; + + public FileException(String code, Object[] args) { + super("file", code, args, null); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/file/FileNameLengthLimitExceededException.java b/zhi-common/src/main/java/com/zhi/common/exception/file/FileNameLengthLimitExceededException.java new file mode 100644 index 0000000..0cd28e1 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/file/FileNameLengthLimitExceededException.java @@ -0,0 +1,14 @@ +package com.zhi.common.exception.file; + +/** + * 文件名称超长限制异常类 + * + * @author ruoyi + */ +public class FileNameLengthLimitExceededException extends FileException { + private static final long serialVersionUID = 1L; + + public FileNameLengthLimitExceededException(int defaultFileNameLength) { + super("upload.filename.exceed.length", new Object[]{defaultFileNameLength}); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/file/FileSizeLimitExceededException.java b/zhi-common/src/main/java/com/zhi/common/exception/file/FileSizeLimitExceededException.java new file mode 100644 index 0000000..de88938 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/file/FileSizeLimitExceededException.java @@ -0,0 +1,14 @@ +package com.zhi.common.exception.file; + +/** + * 文件名大小限制异常类 + * + * @author ruoyi + */ +public class FileSizeLimitExceededException extends FileException { + private static final long serialVersionUID = 1L; + + public FileSizeLimitExceededException(long defaultMaxSize) { + super("upload.exceed.maxSize", new Object[]{defaultMaxSize}); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/user/CaptchaException.java b/zhi-common/src/main/java/com/zhi/common/exception/user/CaptchaException.java new file mode 100644 index 0000000..c99cd00 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/user/CaptchaException.java @@ -0,0 +1,14 @@ +package com.zhi.common.exception.user; + +/** + * 验证码错误异常类 + * + * @author ruoyi + */ +public class CaptchaException extends UserException { + private static final long serialVersionUID = 1L; + + public CaptchaException() { + super("user.jcaptcha.error"); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/user/CaptchaExpireException.java b/zhi-common/src/main/java/com/zhi/common/exception/user/CaptchaExpireException.java new file mode 100644 index 0000000..96ef92c --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/user/CaptchaExpireException.java @@ -0,0 +1,14 @@ +package com.zhi.common.exception.user; + +/** + * 验证码失效异常类 + * + * @author ruoyi + */ +public class CaptchaExpireException extends UserException { + private static final long serialVersionUID = 1L; + + public CaptchaExpireException() { + super("user.jcaptcha.expire"); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/user/UserException.java b/zhi-common/src/main/java/com/zhi/common/exception/user/UserException.java new file mode 100644 index 0000000..23ea320 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/user/UserException.java @@ -0,0 +1,16 @@ +package com.zhi.common.exception.user; + +import com.zhi.common.exception.base.BaseException; + +/** + * 用户信息异常类 + * + * @author ruoyi + */ +public class UserException extends BaseException { + private static final long serialVersionUID = 1L; + + public UserException(String code, Object... args) { + super("user", code, args, null); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/exception/user/UserPasswordNotMatchException.java b/zhi-common/src/main/java/com/zhi/common/exception/user/UserPasswordNotMatchException.java new file mode 100644 index 0000000..99d7ffa --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/user/UserPasswordNotMatchException.java @@ -0,0 +1,15 @@ +package com.zhi.common.exception.user; + +/** + * 用户密码不正确或不符合规范异常类 + * + * @author ruoyi + */ +public class UserPasswordNotMatchException extends UserException { + private static final long serialVersionUID = 1L; + + public UserPasswordNotMatchException() { + super("user.password.not.match"); + } +} + diff --git a/zhi-common/src/main/java/com/zhi/common/exception/user/UserPasswordRetryLimitExceedException.java b/zhi-common/src/main/java/com/zhi/common/exception/user/UserPasswordRetryLimitExceedException.java new file mode 100644 index 0000000..e5533a3 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/exception/user/UserPasswordRetryLimitExceedException.java @@ -0,0 +1,16 @@ +package com.zhi.common.exception.user; + +/** + * 用户错误最大次数异常类 + * + * @author ruoyi + */ +public class UserPasswordRetryLimitExceedException extends UserException { + + private static final long serialVersionUID = 1L; + + public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime) { + super("user.password.retry.limit.exceed", retryLimitCount, lockTime); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/filter/RepeatableFilter.java b/zhi-common/src/main/java/com/zhi/common/filter/RepeatableFilter.java new file mode 100644 index 0000000..531b374 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/filter/RepeatableFilter.java @@ -0,0 +1,41 @@ +package com.zhi.common.filter; + +import com.zhi.common.utils.StringUtils; +import org.springframework.http.MediaType; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +/** + * Repeatable 过滤器 + * + * @author ruoyi + */ +public class RepeatableFilter implements Filter { + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + ServletRequest requestWrapper = null; + if (request instanceof HttpServletRequest + && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) + { + requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); + } + if (null == requestWrapper) { + chain.doFilter(request, response); + } else { + chain.doFilter(requestWrapper, response); + } + } + + @Override + public void destroy() { + + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/filter/RepeatedlyRequestWrapper.java b/zhi-common/src/main/java/com/zhi/common/filter/RepeatedlyRequestWrapper.java new file mode 100644 index 0000000..6bca336 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/filter/RepeatedlyRequestWrapper.java @@ -0,0 +1,67 @@ +package com.zhi.common.filter; + +import cn.hutool.core.io.IoUtil; +import com.zhi.common.constant.Constants; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + +/** + * 构建可重复读取inputStream的request + * + * @author ruoyi + */ +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { + private final byte[] body; + + public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { + super(request); + request.setCharacterEncoding(Constants.UTF8); + response.setCharacterEncoding(Constants.UTF8); + + body = IoUtil.readBytes(request.getInputStream(), false); + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + final ByteArrayInputStream bais = new ByteArrayInputStream(body); + return new ServletInputStream() { + @Override + public int read() throws IOException { + return bais.read(); + } + + @Override + public int available() throws IOException { + return body.length; + } + + @Override + public boolean isFinished() { + return false; + } + + @Override + public boolean isReady() { + return false; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + }; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/filter/XssFilter.java b/zhi-common/src/main/java/com/zhi/common/filter/XssFilter.java new file mode 100644 index 0000000..685942f --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/filter/XssFilter.java @@ -0,0 +1,62 @@ +package com.zhi.common.filter; + +import com.zhi.common.enums.HttpMethod; +import com.zhi.common.utils.StringUtils; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 防止XSS攻击的过滤器 + * + * @author ruoyi + */ +public class XssFilter implements Filter { + /** + * 排除链接 + */ + public List excludes = new ArrayList<>(); + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + String tempExcludes = filterConfig.getInitParameter("excludes"); + if (StringUtils.isNotEmpty(tempExcludes)) { + String[] url = tempExcludes.split(","); + for (int i = 0; url != null && i < url.length; i++) { + excludes.add(url[i]); + } + } + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + HttpServletResponse resp = (HttpServletResponse) response; + if (handleExcludeURL(req, resp)) { + chain.doFilter(request, response); + return; + } + XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request); + chain.doFilter(xssRequest, response); + } + + private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) { + String url = request.getServletPath(); + String method = request.getMethod(); + // GET DELETE 不过滤 + if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method)) { + return true; + } + return StringUtils.matches(url, excludes); + } + + @Override + public void destroy() { + + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/filter/XssHttpServletRequestWrapper.java b/zhi-common/src/main/java/com/zhi/common/filter/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..cd4026c --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/filter/XssHttpServletRequestWrapper.java @@ -0,0 +1,97 @@ +package com.zhi.common.filter; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HtmlUtil; +import com.zhi.common.utils.StringUtils; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * XSS过滤处理 + * + * @author ruoyi + */ +public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { + /** + * @param request + */ + public XssHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + } + + @Override + public String[] getParameterValues(String name) { + String[] values = super.getParameterValues(name); + if (values != null) { + int length = values.length; + String[] escapseValues = new String[length]; + for (int i = 0; i < length; i++) { + // 防xss攻击和过滤前后空格 + escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim(); + } + return escapseValues; + } + return super.getParameterValues(name); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + // 非json类型,直接返回 + if (!isJsonRequest()) { + return super.getInputStream(); + } + + // 为空,直接返回 + String json = StrUtil.str(IoUtil.readBytes(super.getInputStream(), false), StandardCharsets.UTF_8); + if (StringUtils.isEmpty(json)) { + return super.getInputStream(); + } + + // xss过滤 + json = HtmlUtil.cleanHtmlTag(json).trim(); + byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8); + final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes); + return new ServletInputStream() { + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public int available() throws IOException { + return jsonBytes.length; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + + @Override + public int read() throws IOException { + return bis.read(); + } + }; + } + + /** + * 是否是Json请求 + */ + public boolean isJsonRequest() { + String header = super.getHeader(HttpHeaders.CONTENT_TYPE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/helper/DataBaseHelper.java b/zhi-common/src/main/java/com/zhi/common/helper/DataBaseHelper.java new file mode 100644 index 0000000..55dcbef --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/helper/DataBaseHelper.java @@ -0,0 +1,72 @@ +package com.zhi.common.helper; + +import cn.hutool.core.convert.Convert; +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.zhi.common.enums.DataBaseType; +import com.zhi.common.exception.ServiceException; +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +/** + * 数据库助手 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DataBaseHelper { + + private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + + /** + * 获取当前数据库类型 + */ + public static DataBaseType getDataBaseType() { + DataSource dataSource = DS.determineDataSource(); + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return DataBaseType.find(databaseProductName); + } catch (SQLException e) { + throw new ServiceException(e.getMessage()); + } + } + + public static boolean isMySql() { + return DataBaseType.MY_SQL == getDataBaseType(); + } + + public static boolean isOracle() { + return DataBaseType.ORACLE == getDataBaseType(); + } + + public static boolean isPostgerSql() { + return DataBaseType.POSTGRE_SQL == getDataBaseType(); + } + + public static boolean isSqlServer() { + return DataBaseType.SQL_SERVER == getDataBaseType(); + } + + public static String findInSet(Object var1, String var2) { + DataBaseType dataBasyType = getDataBaseType(); + String var = Convert.toStr(var1); + if (dataBasyType == DataBaseType.SQL_SERVER) { + // charindex(',100,' , ',0,100,101,') <> 0 + return "charindex('," + var + ",' , ','+" + var2 + "+',') <> 0"; + } else if (dataBasyType == DataBaseType.POSTGRE_SQL) { + // (select position(',100,' in ',0,100,101,')) <> 0 + return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0"; + } else if (dataBasyType == DataBaseType.ORACLE) { + // instr(',0,100,101,' , ',100,') <> 0 + return "instr(','||" + var2 + "||',' , '," + var + ",') <> 0"; + } + // find_in_set(100 , '0,100,101') + return "find_in_set(" + var + " , " + var2 + ") <> 0"; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/helper/DataPermissionHelper.java b/zhi-common/src/main/java/com/zhi/common/helper/DataPermissionHelper.java new file mode 100644 index 0000000..e44561d --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/helper/DataPermissionHelper.java @@ -0,0 +1,47 @@ +package com.zhi.common.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.context.model.SaStorage; +import cn.hutool.core.util.ObjectUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * 数据权限助手 + * + * @author Lion Li + * @version 3.5.0 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings("unchecked cast") +public class DataPermissionHelper { + + private static final String DATA_PERMISSION_KEY = "data:permission"; + + public static T getVariable(String key) { + Map context = getContext(); + return (T) context.get(key); + } + + + public static void setVariable(String key, Object value) { + Map context = getContext(); + context.put(key, value); + } + + public static Map getContext() { + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); + attribute = saStorage.get(DATA_PERMISSION_KEY); + } + if (attribute instanceof Map) { + return (Map) attribute; + } + throw new NullPointerException("data permission context type exception"); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/helper/LoginHelper.java b/zhi-common/src/main/java/com/zhi/common/helper/LoginHelper.java new file mode 100644 index 0000000..e3fe491 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/helper/LoginHelper.java @@ -0,0 +1,137 @@ +package com.zhi.common.helper; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.zhi.common.constant.UserConstants; +import com.zhi.common.core.domain.model.BlogLoginUser; +import com.zhi.common.core.domain.model.LoginUser; +import com.zhi.common.enums.DeviceType; +import com.zhi.common.enums.UserType; +import com.zhi.common.exception.UtilException; +import com.zhi.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * 登录鉴权助手 + * + * user_type 为 用户类型 同一个用户表 可以有多种用户类型 例如 pc,app + * deivce 为 设备类型 同一个用户类型 可以有 多种设备类型 例如 web,ios + * 可以组成 用户类型与设备类型多对多的 权限灵活控制 + * + * 多用户体系 针对 多种用户类型 但权限控制不一致 + * 可以组成 多用户类型表与多设备类型 分别控制权限 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class LoginHelper { + + public static final String JOIN_CODE = ":"; + public static final String LOGIN_USER_KEY = "loginUser"; + + public static final String BLOG_LOGIN_USER_KEY = "blogLoginUser"; + + /** + * 登录系统 + * + * @param loginUser 登录用户信息 + */ + public static void login(LoginUser loginUser) { + SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); + StpUtil.login(loginUser.getLoginId()); + setLoginUser(loginUser); + } + + /** + * 登录系统 基于 设备类型 + * 针对相同用户体系不同设备 + * + * @param loginUser 登录用户信息 + */ + public static void loginByDevice(LoginUser loginUser, DeviceType deviceType) { + SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); + StpUtil.login(loginUser.getLoginId(), deviceType.getDevice()); + setLoginUser(loginUser); + } + + + + + /** + * 设置用户数据(多级缓存) + */ + public static void setLoginUser(LoginUser loginUser) { + StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser); + } + + + /** + * 获取用户(多级缓存) + */ + public static LoginUser getLoginUser() { + LoginUser loginUser = (LoginUser) SaHolder.getStorage().get(LOGIN_USER_KEY); + if (loginUser != null) { + return loginUser; + } + loginUser = (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY); + SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser); + return loginUser; + } + + /** + * 获取用户id + */ + public static Long getUserId() { + LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + String loginId = StpUtil.getLoginIdAsString(); + String[] strs = StringUtils.split(loginId, JOIN_CODE); + if (!ArrayUtil.containsAny(strs, UserType.values())) { + throw new UtilException("登录用户: LoginId异常 => " + loginId); + } + // 用户id在总是在最后 + return Long.parseLong(strs[strs.length - 1]); + } + return loginUser.getUserId(); + } + + /** + * 获取部门ID + */ + public static Long getDeptId() { + return getLoginUser().getDeptId(); + } + + /** + * 获取用户账户 + */ + public static String getUsername() { + return getLoginUser().getUsername(); + } + + /** + * 获取用户类型 + */ + public static UserType getUserType() { + String loginId = StpUtil.getLoginIdAsString(); + return UserType.getUserType(loginId); + } + + /** + * 是否为管理员 + * + * @param userId 用户ID + * @return 结果 + */ + public static boolean isAdmin(Long userId) { + return UserConstants.ADMIN_ID.equals(userId); + } + + public static boolean isAdmin() { + return isAdmin(getUserId()); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/jackson/DictDataJsonSerializer.java b/zhi-common/src/main/java/com/zhi/common/jackson/DictDataJsonSerializer.java new file mode 100644 index 0000000..8747b51 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/jackson/DictDataJsonSerializer.java @@ -0,0 +1,56 @@ +package com.zhi.common.jackson; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.zhi.common.annotation.DictDataMapper; +import com.zhi.common.core.service.DictService; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; + +import java.io.IOException; +import java.util.Objects; + +/** + * 字典数据json序列化工具 + * + * @author itino + */ +@Slf4j +public class DictDataJsonSerializer extends JsonSerializer implements ContextualSerializer { + + private String dictType; + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + try { + DictService dictService = SpringUtils.getBean(DictService.class); + if (ObjectUtil.isNotNull(dictService)) { + String label = dictService.getDictLabel(dictType, value); + gen.writeString(StringUtils.isNotBlank(label) ? label : value); + } else { + gen.writeString(value); + } + } catch (BeansException e) { + log.error("字典数据未查到, 采用默认处理 => {}", e.getMessage()); + gen.writeString(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + DictDataMapper anno = property.getAnnotation(DictDataMapper.class); + if (Objects.nonNull(anno) && StrUtil.isNotBlank(anno.dictType())) { + this.dictType = anno.dictType(); + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/jackson/SensitiveJsonSerializer.java b/zhi-common/src/main/java/com/zhi/common/jackson/SensitiveJsonSerializer.java new file mode 100644 index 0000000..a8f0a39 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/jackson/SensitiveJsonSerializer.java @@ -0,0 +1,54 @@ +package com.zhi.common.jackson; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.zhi.common.annotation.Sensitive; +import com.zhi.common.core.service.SensitiveService; +import com.zhi.common.enums.SensitiveStrategy; +import com.zhi.common.utils.spring.SpringUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; + +import java.io.IOException; +import java.util.Objects; + +/** + * 数据脱敏json序列化工具 + * + * @author Yjoioooo + */ +@Slf4j +public class SensitiveJsonSerializer extends JsonSerializer implements ContextualSerializer { + + private SensitiveStrategy strategy; + + @Override + public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + try { + SensitiveService sensitiveService = SpringUtils.getBean(SensitiveService.class); + if (ObjectUtil.isNotNull(sensitiveService) && sensitiveService.isSensitive()) { + gen.writeString(strategy.desensitizer().apply(value)); + } else { + gen.writeString(value); + } + } catch (BeansException e) { + log.error("脱敏实现不存在, 采用默认处理 => {}", e.getMessage()); + gen.writeString(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + Sensitive annotation = property.getAnnotation(Sensitive.class); + if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass())) { + this.strategy = annotation.strategy(); + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/TranslationInterface.java b/zhi-common/src/main/java/com/zhi/common/translation/TranslationInterface.java new file mode 100644 index 0000000..e16100b --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/TranslationInterface.java @@ -0,0 +1,17 @@ +package com.zhi.common.translation; + +/** + * 翻译接口 (实现类需标注 {@link com.ruoyi.common.annotation.TranslationType} 注解标明翻译类型) + * + * @author Lion Li + */ +public interface TranslationInterface { + + /** + * 翻译 + * + * @param key 需要被翻译的键(不为空) + * @return 返回键对应的值 + */ + T translation(Object key, String other); +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/handler/TranslationBeanSerializerModifier.java b/zhi-common/src/main/java/com/zhi/common/translation/handler/TranslationBeanSerializerModifier.java new file mode 100644 index 0000000..c8d9ba2 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/handler/TranslationBeanSerializerModifier.java @@ -0,0 +1,29 @@ +package com.zhi.common.translation.handler; + +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; + +import java.util.List; + +/** + * Bean 序列化修改器 解决 Null 被单独处理问题 + * + * @author Lion Li + */ +public class TranslationBeanSerializerModifier extends BeanSerializerModifier { + + @Override + public List changeProperties(SerializationConfig config, BeanDescription beanDesc, + List beanProperties) { + for (BeanPropertyWriter writer : beanProperties) { + // 如果序列化器为 TranslationHandler 的话 将 Null 值也交给他处理 + if (writer.getSerializer() instanceof TranslationHandler) { + writer.assignNullSerializer(writer.getSerializer()); + } + } + return beanProperties; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/handler/TranslationHandler.java b/zhi-common/src/main/java/com/zhi/common/translation/handler/TranslationHandler.java new file mode 100644 index 0000000..24f3d55 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/handler/TranslationHandler.java @@ -0,0 +1,65 @@ +package com.zhi.common.translation.handler; + +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import com.zhi.common.annotation.Translation; +import com.zhi.common.translation.TranslationInterface; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.reflect.ReflectUtils; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 翻译处理器 + * + * @author Lion Li + */ +@Slf4j +public class TranslationHandler extends JsonSerializer implements ContextualSerializer { + + /** + * 全局翻译实现类映射器 + */ + public static final Map> TRANSLATION_MAPPER = new ConcurrentHashMap<>(); + + private Translation translation; + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + TranslationInterface trans = TRANSLATION_MAPPER.get(translation.type()); + if (ObjectUtil.isNotNull(trans)) { + // 如果映射字段不为空 则取映射字段的值 + if (StringUtils.isNotBlank(translation.mapper())) { + value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper()); + } + // 如果为 null 直接写出 + if (ObjectUtil.isNull(value)) { + gen.writeNull(); + return; + } + Object result = trans.translation(value, translation.other()); + gen.writeObject(result); + } else { + gen.writeObject(value); + } + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + Translation translation = property.getAnnotation(Translation.class); + if (Objects.nonNull(translation)) { + this.translation = translation; + return this; + } + return prov.findValueSerializer(property.getType(), property); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/impl/DeptNameTranslationImpl.java b/zhi-common/src/main/java/com/zhi/common/translation/impl/DeptNameTranslationImpl.java new file mode 100644 index 0000000..cea20d2 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/impl/DeptNameTranslationImpl.java @@ -0,0 +1,24 @@ +package com.zhi.common.translation.impl; +import com.zhi.common.annotation.TranslationType; +import com.zhi.common.constant.TransConstant; +import com.zhi.common.core.service.DeptService; +import com.zhi.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 部门翻译实现 + * + * @author Lion Li + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.DEPT_ID_TO_NAME) +public class DeptNameTranslationImpl implements TranslationInterface { + + private final DeptService deptService; + + public String translation(Object key, String other) { + return deptService.selectDeptNameByIds(key.toString()); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/impl/DictTypeTranslationImpl.java b/zhi-common/src/main/java/com/zhi/common/translation/impl/DictTypeTranslationImpl.java new file mode 100644 index 0000000..c584519 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/impl/DictTypeTranslationImpl.java @@ -0,0 +1,29 @@ +package com.zhi.common.translation.impl; + +import com.zhi.common.annotation.TranslationType; +import com.zhi.common.constant.TransConstant; +import com.zhi.common.core.service.DictService; +import com.zhi.common.translation.TranslationInterface; +import com.zhi.common.utils.StringUtils; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 字典翻译实现 + * + * @author Lion Li + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.DICT_TYPE_TO_LABEL) +public class DictTypeTranslationImpl implements TranslationInterface { + + private final DictService dictService; + + public String translation(Object key, String other) { + if (key instanceof String && StringUtils.isNotBlank(other)) { + return dictService.getDictLabel(other, key.toString()); + } + return null; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/impl/OssUrlTranslationImpl.java b/zhi-common/src/main/java/com/zhi/common/translation/impl/OssUrlTranslationImpl.java new file mode 100644 index 0000000..415b015 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/impl/OssUrlTranslationImpl.java @@ -0,0 +1,24 @@ +package com.zhi.common.translation.impl; +import com.zhi.common.annotation.TranslationType; +import com.zhi.common.constant.TransConstant; +import com.zhi.common.core.service.OssService; +import com.zhi.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * OSS翻译实现 + * + * @author Lion Li + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.OSS_ID_TO_URL) +public class OssUrlTranslationImpl implements TranslationInterface { + + private final OssService ossService; + + public String translation(Object key, String other) { + return ossService.selectUrlByIds(key.toString()); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/translation/impl/UserNameTranslationImpl.java b/zhi-common/src/main/java/com/zhi/common/translation/impl/UserNameTranslationImpl.java new file mode 100644 index 0000000..76727f4 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/translation/impl/UserNameTranslationImpl.java @@ -0,0 +1,28 @@ +package com.zhi.common.translation.impl; + +import com.zhi.common.annotation.TranslationType; +import com.zhi.common.constant.TransConstant; +import com.zhi.common.core.service.UserService; +import com.zhi.common.translation.TranslationInterface; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Component; + +/** + * 用户名翻译实现 + * + * @author Lion Li + */ +@Component +@AllArgsConstructor +@TranslationType(type = TransConstant.USER_ID_TO_NAME) +public class UserNameTranslationImpl implements TranslationInterface { + + private final UserService userService; + + public String translation(Object key, String other) { + if (key instanceof Long) { + return userService.selectUserNameById((Long) key); + } + return null; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/BeanCopyUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/BeanCopyUtils.java new file mode 100644 index 0000000..d11926a --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/BeanCopyUtils.java @@ -0,0 +1,204 @@ +package com.zhi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.SimpleCache; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.cglib.beans.BeanCopier; +import org.springframework.cglib.beans.BeanMap; +import org.springframework.cglib.core.Converter; + +import java.util.List; +import java.util.Map; + +/** + * bean深拷贝工具(基于 cglib 性能优异) + *

+ * 重点 cglib 不支持 拷贝到链式对象 + * 例如: 源对象 拷贝到 目标(链式对象) + * 请区分好`浅拷贝`和`深拷贝`再做使用 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class BeanCopyUtils { + + /** + * 复制对象 + * + * @param source 源 + * @param target 目标 + * @return {@link T} + */ + public static T copyObject(Object source, Class target) { + T temp = null; + try { + temp = target.newInstance(); + if (null != source) { + org.springframework.beans.BeanUtils.copyProperties(source, temp); + } + } catch (Exception e) { + e.printStackTrace(); + } + return temp; + } + + /** + * 单对象基于class创建拷贝 + * + * @param source 数据来源实体 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static V copy(T source, Class desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + final V target = ReflectUtil.newInstanceIfPossible(desc); + return copy(source, target); + } + + /** + * 单对象基于对象创建拷贝 + * + * @param source 数据来源实体 + * @param desc 转换后的对象 + * @return desc + */ + public static V copy(T source, V desc) { + if (ObjectUtil.isNull(source)) { + return null; + } + if (ObjectUtil.isNull(desc)) { + return null; + } + BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null); + beanCopier.copy(source, desc, null); + return desc; + } + + /** + * 列表对象基于class创建拷贝 + * + * @param sourceList 数据来源实体列表 + * @param desc 描述对象 转换后的对象 + * @return desc + */ + public static List copyList(List sourceList, Class desc) { + if (ObjectUtil.isNull(sourceList)) { + return null; + } + if (CollUtil.isEmpty(sourceList)) { + return CollUtil.newArrayList(); + } + return StreamUtils.toList(sourceList, source -> { + V target = ReflectUtil.newInstanceIfPossible(desc); + copy(source, target); + return target; + }); + } + + /** + * bean拷贝到map + * + * @param bean 数据来源实体 + * @return map对象 + */ + @SuppressWarnings("unchecked") + public static Map copyToMap(T bean) { + if (ObjectUtil.isNull(bean)) { + return null; + } + return BeanMap.create(bean); + } + + /** + * map拷贝到bean + * + * @param map 数据来源 + * @param beanClass bean类 + * @return bean对象 + */ + public static T mapToBean(Map map, Class beanClass) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(beanClass)) { + return null; + } + T bean = ReflectUtil.newInstanceIfPossible(beanClass); + return mapToBean(map, bean); + } + + /** + * map拷贝到bean + * + * @param map 数据来源 + * @param bean bean对象 + * @return bean对象 + */ + public static T mapToBean(Map map, T bean) { + if (MapUtil.isEmpty(map)) { + return null; + } + if (ObjectUtil.isNull(bean)) { + return null; + } + BeanMap.create(bean).putAll(map); + return bean; + } + + /** + * BeanCopier属性缓存
+ * 缓存用于防止多次反射造成的性能问题 + * + * @author Looly + * @since 5.4.1 + */ + public enum BeanCopierCache { + /** + * BeanCopier属性缓存单例 + */ + INSTANCE; + + private final SimpleCache cache = new SimpleCache<>(); + + /** + * 获得类与转换器生成的key在{@link BeanCopier}的Map中对应的元素 + * + * @param srcClass 源Bean的类 + * @param targetClass 目标Bean的类 + * @param converter 转换器 + * @return Map中对应的BeanCopier + */ + public BeanCopier get(Class srcClass, Class targetClass, Converter converter) { + final String key = genKey(srcClass, targetClass, converter); + return cache.get(key, () -> BeanCopier.create(srcClass, targetClass, converter != null)); + } + + /** + * 获得类与转换器生成的key + * + * @param srcClass 源Bean的类 + * @param targetClass 目标Bean的类 + * @param converter 转换器 + * @return 属性名和Map映射的key + */ + private String genKey(Class srcClass, Class targetClass, Converter converter) { + final StringBuilder key = StrUtil.builder() + .append(srcClass.getName()).append('#').append(targetClass.getName()); + if(null != converter){ + key.append('#').append(converter.getClass().getName()); + } + return key.toString(); + } + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/DateUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/DateUtils.java new file mode 100644 index 0000000..8c209fe --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/DateUtils.java @@ -0,0 +1,168 @@ +package com.zhi.common.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.time.DateFormatUtils; + +import java.lang.management.ManagementFactory; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Date; + +/** + * 时间工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + + public static final String YYYY = "yyyy"; + + public static final String YYYY_MM = "yyyy-MM"; + + public static final String YYYY_MM_DD = "yyyy-MM-dd"; + + public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss"; + + public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss"; + + private static final String[] PARSE_PATTERNS = { + "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", + "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", + "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"}; + + /** + * 获取当前Date型日期 + * + * @return Date() 当前日期 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取当前日期, 默认格式为yyyy-MM-dd + * + * @return String + */ + public static String getDate() { + return dateTimeNow(YYYY_MM_DD); + } + + public static String getTime() { + return dateTimeNow(YYYY_MM_DD_HH_MM_SS); + } + + public static String dateTimeNow() { + return dateTimeNow(YYYYMMDDHHMMSS); + } + + public static String dateTimeNow(final String format) { + return parseDateToStr(format, new Date()); + } + + public static String dateTime(final Date date) { + return parseDateToStr(YYYY_MM_DD, date); + } + + public static String parseDateToStr(final String format, final Date date) { + return new SimpleDateFormat(format).format(date); + } + + public static Date dateTime(final String format, final String ts) { + try { + return new SimpleDateFormat(format).parse(ts); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * 日期路径 即年/月/日 如2018/08/08 + */ + public static String datePath() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyy/MM/dd"); + } + + /** + * 日期路径 即年/月/日 如20180808 + */ + public static String dateTime() { + Date now = new Date(); + return DateFormatUtils.format(now, "yyyyMMdd"); + } + + /** + * 日期型字符串转化为日期 格式 + */ + public static Date parseDate(Object str) { + if (str == null) { + return null; + } + try { + return parseDate(str.toString(), PARSE_PATTERNS); + } catch (ParseException e) { + return null; + } + } + + /** + * 获取服务器启动时间 + */ + public static Date getServerStartDate() { + long time = ManagementFactory.getRuntimeMXBean().getStartTime(); + return new Date(time); + } + + /** + * 计算相差天数 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + + /** + * 计算两个时间差 + */ + public static String getDatePoor(Date endDate, Date nowDate) { + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // long ns = 1000; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - nowDate.getTime(); + // 计算差多少天 + long day = diff / nd; + // 计算差多少小时 + long hour = diff % nd / nh; + // 计算差多少分钟 + long min = diff % nd % nh / nm; + // 计算差多少秒//输出结果 + // long sec = diff % nd % nh % nm / ns; + return day + "天" + hour + "小时" + min + "分钟"; + } + + /** + * 增加 LocalDateTime ==> Date + */ + public static Date toDate(LocalDateTime temporalAccessor) { + ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } + + /** + * 增加 LocalDate ==> Date + */ + public static Date toDate(LocalDate temporalAccessor) { + LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0)); + ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault()); + return Date.from(zdt.toInstant()); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/JsonUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/JsonUtils.java new file mode 100644 index 0000000..dc8a478 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/JsonUtils.java @@ -0,0 +1,112 @@ +package com.zhi.common.utils; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.ObjectUtil; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.exc.MismatchedInputException; +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * JSON 工具类 + * + * @author 芋道源码 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class JsonUtils { + + private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class); + + public static ObjectMapper getObjectMapper() { + return OBJECT_MAPPER; + } + + public static String toJsonString(Object object) { + if (ObjectUtil.isNull(object)) { + return null; + } + try { + return OBJECT_MAPPER.writeValueAsString(object); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(byte[] bytes, Class clazz) { + if (ArrayUtil.isEmpty(bytes)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(bytes, clazz); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static T parseObject(String text, TypeReference typeReference) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Dict parseMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class)); + } catch (MismatchedInputException e) { + // 类型不匹配说明不是json + return null; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static List parseArrayMap(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static List parseArray(String text, Class clazz) { + if (StringUtils.isEmpty(text)) { + return new ArrayList<>(); + } + try { + return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/MessageUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/MessageUtils.java new file mode 100644 index 0000000..baf0040 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/MessageUtils.java @@ -0,0 +1,29 @@ +package com.zhi.common.utils; + +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 获取i18n资源文件 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MessageUtils { + + private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class); + + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) { + return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale()); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/ServletUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/ServletUtils.java new file mode 100644 index 0000000..057746d --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/ServletUtils.java @@ -0,0 +1,203 @@ +package com.zhi.common.utils; + +import cn.hutool.core.convert.Convert; +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.HttpStatus; +import com.zhi.common.constant.Constants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * 客户端工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ServletUtils extends ServletUtil { + + /** + * 获取String参数 + */ + public static String getParameter(String name) { + return getRequest().getParameter(name); + } + + /** + * 获取String参数 + */ + public static String getParameter(String name, String defaultValue) { + return Convert.toStr(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name) { + return Convert.toInt(getRequest().getParameter(name)); + } + + /** + * 获取Integer参数 + */ + public static Integer getParameterToInt(String name, Integer defaultValue) { + return Convert.toInt(getRequest().getParameter(name), defaultValue); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name) { + return Convert.toBool(getRequest().getParameter(name)); + } + + /** + * 获取Boolean参数 + */ + public static Boolean getParameterToBool(String name, Boolean defaultValue) { + return Convert.toBool(getRequest().getParameter(name), defaultValue); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParams(ServletRequest request) { + final Map map = request.getParameterMap(); + return Collections.unmodifiableMap(map); + } + + /** + * 获得所有请求参数 + * + * @param request 请求对象{@link ServletRequest} + * @return Map + */ + public static Map getParamMap(ServletRequest request) { + Map params = new HashMap<>(); + for (Map.Entry entry : getParams(request).entrySet()) { + params.put(entry.getKey(), StringUtils.join(entry.getValue(), ",")); + } + return params; + } + + /** + * 获取request + */ + public static HttpServletRequest getRequest() { + return getRequestAttributes().getRequest(); + } + + /** + * 获取response + */ + public static HttpServletResponse getResponse() { + return getRequestAttributes().getResponse(); + } + + /** + * 获取session + */ + public static HttpSession getSession() { + return getRequest().getSession(); + } + + public static ServletRequestAttributes getRequestAttributes() { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + return (ServletRequestAttributes) attributes; + } + + /** + * 将字符串渲染到客户端 + * + * @param response 渲染对象 + * @param string 待渲染的字符串 + */ + public static void renderString(HttpServletResponse response, String string) { + try { + response.setStatus(HttpStatus.HTTP_OK); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); + response.getWriter().print(string); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * 是否是Ajax异步请求 + * + * @param request + */ + public static boolean isAjaxRequest(HttpServletRequest request) { + + String accept = request.getHeader("accept"); + if (accept != null && accept.contains(MediaType.APPLICATION_JSON_VALUE)) { + return true; + } + + String xRequestedWith = request.getHeader("X-Requested-With"); + if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest")) { + return true; + } + + String uri = request.getRequestURI(); + if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { + return true; + } + + String ajax = request.getParameter("__ajax"); + return StringUtils.equalsAnyIgnoreCase(ajax, "json", "xml"); + } + + public static String getClientIP() { + return getClientIP(getRequest()); + } + + /** + * 内容编码 + * + * @param str 内容 + * @return 编码后的内容 + */ + public static String urlEncode(String str) { + try { + return URLEncoder.encode(str, Constants.UTF8); + } catch (UnsupportedEncodingException e) { + return StringUtils.EMPTY; + } + } + + /** + * 内容解码 + * + * @param str 内容 + * @return 解码后的内容 + */ + public static String urlDecode(String str) { + try { + return URLDecoder.decode(str, Constants.UTF8); + } catch (UnsupportedEncodingException e) { + return StringUtils.EMPTY; + } + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/StreamUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/StreamUtils.java new file mode 100644 index 0000000..fbb74b1 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/StreamUtils.java @@ -0,0 +1,251 @@ +package com.zhi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * stream 流工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StreamUtils { + + /** + * 将collection过滤 + * + * @param collection 需要转化的集合 + * @param function 过滤方法 + * @return 过滤后的list + */ + public static List filter(Collection collection, Predicate function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection.stream().filter(function).collect(Collectors.toList()); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function) { + return join(collection, function, ","); + } + + /** + * 将collection拼接 + * + * @param collection 需要转化的集合 + * @param function 拼接方法 + * @param delimiter 拼接符 + * @return 拼接后的list + */ + public static String join(Collection collection, Function function, CharSequence delimiter) { + if (CollUtil.isEmpty(collection)) { + return StringUtils.EMPTY; + } + return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter)); + } + + /** + * 将collection排序 + * + * @param collection 需要转化的集合 + * @param comparing 排序方法 + * @return 排序后的list + */ + public static List sorted(Collection collection, Comparator comparing) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection.stream().sorted(comparing).collect(Collectors.toList()); + } + + /** + * 将collection转化为类型不变的map
+ * {@code Collection ----> Map} + * + * @param collection 需要转化的集合 + * @param key V类型转化为K类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @return 转化后的map + */ + public static Map toIdentityMap(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l)); + } + + /** + * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map } + * + * @param collection 需要转化的集合 + * @param key E类型转化为K类型的lambda方法 + * @param value E类型转化为V类型的lambda方法 + * @param collection中的泛型 + * @param map中的key类型 + * @param map中的value类型 + * @return 转化后的map + */ + public static Map toMap(Collection collection, Function key, Function value) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l)); + } + + /** + * 将collection按照规则(比如有相同的班级id)分类成map
+ * {@code Collection -------> Map> } + * + * @param collection 需要分类的集合 + * @param key 分类的规则 + * @param collection中的泛型 + * @param map中的key类型 + * @return 分类后的map + */ + public static Map> groupByKey(Collection collection, Function key) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream() + .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList())); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map>> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 集合元素类型 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @return 分类后的map + */ + public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection)) { + return MapUtil.newHashMap(); + } + return collection + .stream() + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList()))); + } + + /** + * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map> } + * + * @param collection 需要分类的集合 + * @param key1 第一个分类的规则 + * @param key2 第二个分类的规则 + * @param 第一个map中的key类型 + * @param 第二个map中的key类型 + * @param collection中的泛型 + * @return 分类后的map + */ + public static Map> group2Map(Collection collection, Function key1, Function key2) { + if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) { + return MapUtil.newHashMap(); + } + return collection + .stream() + .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l))); + } + + /** + * 将collection转化为List集合,但是两者的泛型不同
+ * {@code Collection ------> List } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为list泛型的lambda表达式 + * @param collection中的泛型 + * @param List中的泛型 + * @return 转化后的list + */ + public static List toList(Collection collection, Function function) { + if (CollUtil.isEmpty(collection)) { + return CollUtil.newArrayList(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } + + /** + * 将collection转化为Set集合,但是两者的泛型不同
+ * {@code Collection ------> Set } + * + * @param collection 需要转化的集合 + * @param function collection中的泛型转化为set泛型的lambda表达式 + * @param collection中的泛型 + * @param Set中的泛型 + * @return 转化后的Set + */ + public static Set toSet(Collection collection, Function function) { + if (CollUtil.isEmpty(collection) || function == null) { + return CollUtil.newHashSet(); + } + return collection + .stream() + .map(function) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + + /** + * 合并两个相同key类型的map + * + * @param map1 第一个需要合并的 map + * @param map2 第二个需要合并的 map + * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况 + * @param map中的key类型 + * @param 第一个 map的value类型 + * @param 第二个 map的value类型 + * @param 最终map的value类型 + * @return 合并后的map + */ + public static Map merge(Map map1, Map map2, BiFunction merge) { + if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) { + return MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map1)) { + map1 = MapUtil.newHashMap(); + } else if (MapUtil.isEmpty(map2)) { + map2 = MapUtil.newHashMap(); + } + Set key = new HashSet<>(); + key.addAll(map1.keySet()); + key.addAll(map2.keySet()); + Map map = new HashMap<>(); + for (K t : key) { + X x = map1.get(t); + Y y = map2.get(t); + V z = merge.apply(x, y); + if (z != null) { + map.put(t, z); + } + } + return map; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/StringUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/StringUtils.java new file mode 100644 index 0000000..0373615 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/StringUtils.java @@ -0,0 +1,325 @@ +package com.zhi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Validator; +import cn.hutool.core.util.StrUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.util.AntPathMatcher; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 字符串工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class StringUtils extends org.apache.commons.lang3.StringUtils { + + public static final String SEPARATOR = ","; + + /** + * 获取参数不为空值 + * + * @param str defaultValue 要判断的value + * @return value 返回值 + */ + public static String blankToDefault(String str, String defaultValue) { + return StrUtil.blankToDefault(str, defaultValue); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) { + return StrUtil.isEmpty(str); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * 去空格 + */ + public static String trim(String str) { + return StrUtil.trim(str); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) { + return substring(str, start, str.length()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) { + return StrUtil.sub(str, start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is {} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) { + return StrUtil.format(template, params); + } + + /** + * 是否为http(s)://开头 + * + * @param link 链接 + * @return 结果 + */ + public static boolean ishttp(String link) { + return Validator.isUrl(link); + } + + /** + * 字符串转set + * + * @param str 字符串 + * @param sep 分隔符 + * @return set集合 + */ + public static Set str2Set(String str, String sep) { + return new HashSet<>(str2List(str, sep, true, false)); + } + + /** + * 字符串转list + * + * @param str 字符串 + * @param sep 分隔符 + * @param filterBlank 过滤纯空白 + * @param trim 去掉首尾空白 + * @return list集合 + */ + public static List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList<>(); + if (isEmpty(str)) { + return list; + } + + // 过滤空白字符串 + if (filterBlank && isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && isBlank(string)) { + continue; + } + if (trim) { + string = trim(string); + } + list.add(string); + } + + return list; + } + + /** + * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + * + * @param cs 指定字符串 + * @param searchCharSequences 需要检查的字符串数组 + * @return 是否包含任意一个字符串 + */ + public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) { + return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences); + } + + /** + * 驼峰转下划线命名 + */ + public static String toUnderScoreCase(String str) { + return StrUtil.toUnderlineCase(str); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + return StrUtil.equalsAnyIgnoreCase(str, strs); + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) { + return StrUtil.upperFirst(StrUtil.toCamelCase(name)); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) { + return StrUtil.toCamelCase(s); + } + + /** + * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串 + * + * @param str 指定字符串 + * @param strs 需要检查的字符串数组 + * @return 是否匹配 + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || CollUtil.isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * 判断url是否与规则配置: + * ? 表示单个字符; + * * 表示一层路径内的任意字符串,不可跨层级; + * ** 表示任意层路径; + * + * @param pattern 匹配规则 + * @param url 需要匹配的url + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + /** + * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。 + * + * @param num 数字对象 + * @param size 字符串指定长度 + * @return 返回数字的字符串格式,该字符串为指定长度。 + */ + public static String padl(final Number num, final int size) { + return padl(num.toString(), size, '0'); + } + + /** + * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。 + * + * @param s 原始字符串 + * @param size 字符串指定长度 + * @param c 用于补齐的字符 + * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。 + */ + public static String padl(final String s, final int size, final char c) { + final StringBuilder sb = new StringBuilder(size); + if (s != null) { + final int len = s.length(); + if (s.length() <= size) { + for (int i = size - len; i > 0; i--) { + sb.append(c); + } + sb.append(s); + } else { + return s.substring(len - size, len); + } + } else { + for (int i = size; i > 0; i--) { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 切分字符串(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @return 分割后的数据列表 + */ + public static List splitList(String str) { + return splitTo(str, Convert::toStr); + } + + /** + * 切分字符串 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @return 分割后的数据列表 + */ + public static List splitList(String str, String separator) { + return splitTo(str, separator, Convert::toStr); + } + + /** + * 切分字符串自定义转换(分隔符默认逗号) + * + * @param str 被切分的字符串 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, Function mapper) { + return splitTo(str, SEPARATOR, mapper); + } + + /** + * 切分字符串自定义转换 + * + * @param str 被切分的字符串 + * @param separator 分隔符 + * @param mapper 自定义转换 + * @return 分割后的数据列表 + */ + public static List splitTo(String str, String separator, Function mapper) { + if (isBlank(str)) { + return new ArrayList<>(0); + } + return StrUtil.split(str, separator) + .stream() + .filter(Objects::nonNull) + .map(mapper) + .collect(Collectors.toList()); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/Threads.java b/zhi-common/src/main/java/com/zhi/common/utils/Threads.java new file mode 100644 index 0000000..ee3e4fa --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/Threads.java @@ -0,0 +1,75 @@ +package com.zhi.common.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.concurrent.*; + +/** + * 线程相关工具类. + * + * @author ruoyi + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Threads { + + /** + * sleep等待,单位为毫秒 + */ + public static void sleep(long milliseconds) { + try { + Thread.sleep(milliseconds); + } catch (InterruptedException e) { + return; + } + } + + /** + * 停止线程池 + * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务. + * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数. + * 如果仍然超時,則強制退出. + * 另对在shutdown时线程本身被调用中断做了处理. + */ + public static void shutdownAndAwaitTermination(ExecutorService pool) { + if (pool != null && !pool.isShutdown()) { + pool.shutdown(); + try { + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + pool.shutdownNow(); + if (!pool.awaitTermination(120, TimeUnit.SECONDS)) { + log.info("Pool did not terminate"); + } + } + } catch (InterruptedException ie) { + pool.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + } + + /** + * 打印线程异常信息 + */ + public static void printException(Runnable r, Throwable t) { + if (t == null && r instanceof Future) { + try { + Future future = (Future) r; + if (future.isDone()) { + future.get(); + } + } catch (CancellationException ce) { + t = ce; + } catch (ExecutionException ee) { + t = ee.getCause(); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (t != null) { + log.error(t.getMessage(), t); + } + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/TreeBuildUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/TreeBuildUtils.java new file mode 100644 index 0000000..7a11266 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/TreeBuildUtils.java @@ -0,0 +1,35 @@ +package com.zhi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; +import com.zhi.common.utils.reflect.ReflectUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 扩展 hutool TreeUtil 封装系统树构建 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TreeBuildUtils extends TreeUtil { + + /** + * 根据前端定制差异化字段 + */ + public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label"); + + public static List> build(List list, NodeParser nodeParser) { + if (CollUtil.isEmpty(list)) { + return null; + } + K k = ReflectUtils.invokeGetter(list.get(0), "parentId"); + return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/ValidatorUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/ValidatorUtils.java new file mode 100644 index 0000000..5c1cf48 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/ValidatorUtils.java @@ -0,0 +1,29 @@ +package com.zhi.common.utils; + +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validator; +import java.util.Set; + +/** + * Validator 校验框架工具 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ValidatorUtils { + + private static final Validator VALID = SpringUtils.getBean(Validator.class); + + public static void validate(T object, Class... groups) { + Set> validate = VALID.validate(object, groups); + if (!validate.isEmpty()) { + throw new ConstraintViolationException("参数校验异常", validate); + } + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/blog/CommonUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/blog/CommonUtils.java new file mode 100644 index 0000000..559b07f --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/blog/CommonUtils.java @@ -0,0 +1,56 @@ +package com.zhi.common.utils.blog; + +import java.util.Random; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 公共工具类 + * + * @author yezhiqiu + * @date 2021/07/28 + */ +public class CommonUtils { + + /** + * 检测邮箱是否合法 + * + * @param username 用户名 + * @return 合法状态 + */ + public static boolean checkEmail(String username) { + String rule = "^\\w+((-\\w+)|(\\.\\w+))*\\@[A-Za-z0-9]+((\\.|-)[A-Za-z0-9]+)*\\.[A-Za-z0-9]+$"; + //正则表达式的模式 编译正则表达式 + Pattern p = Pattern.compile(rule); + //正则表达式的匹配器 + Matcher m = p.matcher(username); + //进行正则匹配 + return m.matches(); + } + + /** + * 获取括号内容 + * + * @param str str + * @return {@link String} 括号内容 + */ + public static String getBracketsContent(String str) { + return str.substring(str.indexOf("(") + 1, str.indexOf(")")); + } + + /** + * 生成6位随机验证码 + * + * @return 验证码 + */ + public static String getRandomCode() { + StringBuilder str = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < 6; i++) { + str.append(random.nextInt(10)); + } + return str.toString(); + } + + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/blog/HTMLUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/blog/HTMLUtils.java new file mode 100644 index 0000000..e824ced --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/blog/HTMLUtils.java @@ -0,0 +1,43 @@ +package com.zhi.common.utils.blog; + +/** + * HTML工具类 + * + * @author yezhiqiu + * @date 2021/07/27 + */ +public class HTMLUtils { + + /** + * 删除标签 + * + * @param source 需要进行剔除HTML的文本 + * @return 过滤后的内容 + */ + public static String deleteTag(String source) { + // 敏感词过滤 + source = SensitiveUtils.filter(source); + // 保留图片标签 + source = source.replaceAll("(?!<(img).*?>)<.*?>", "") + .replaceAll("(onload(.*?)=)", "") + .replaceAll("(onerror(.*?)=)", ""); + return deleteHMTLTag(source); + } + + /** + * 删除标签 + * + * @param source 文本 + * @return 过滤后的文本 + */ + private static String deleteHMTLTag(String source) { + // 删除转义字符 + source = source.replaceAll("&.{2,6}?;", ""); + // 删除script标签 + source = source.replaceAll("<[\\s]*?script[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?script[\\s]*?>", ""); + // 删除style标签 + source = source.replaceAll("<[\\s]*?style[^>]*?>[\\s\\S]*?<[\\s]*?\\/[\\s]*?style[\\s]*?>", ""); + return source; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/blog/IpUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/blog/IpUtils.java new file mode 100644 index 0000000..5d9d44d --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/blog/IpUtils.java @@ -0,0 +1,99 @@ +package com.zhi.common.utils.blog; + +import com.alibaba.fastjson.JSON; +import eu.bitwalker.useragentutils.UserAgent; + +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Map; + +/** + * ip工具类 + * + * @author 11921 + */ +@SuppressWarnings("all") +public class IpUtils { + + /** + * 获取用户ip地址 + * + * @param request 请求 + * @return ip地址 + */ + public static String getIpAddress(HttpServletRequest request) { + String ipAddress = null; + try { + ipAddress = request.getHeader("x-forwarded-for"); + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + if ("127.0.0.1".equals(ipAddress)) { + // 根据网卡取本机配置的IP + InetAddress inet = null; + try { + inet = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + ipAddress = inet.getHostAddress(); + } + } + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if (ipAddress != null && ipAddress.length() > 15) { + // = 15 + if (ipAddress.indexOf(",") > 0) { + ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); + } + } + } catch (Exception e) { + ipAddress = ""; + } + return ipAddress; + } + + /** + * 解析ip地址 + * + * @param ipAddress ip地址 + * @return 解析后的ip地址 + */ + public static String getIpSource(String ipAddress) { + try { + URL url = new URL("http://opendata.baidu.com/api.php?query=" + ipAddress + "&co=&resource_id=6006&oe=utf8"); + BufferedReader reader = new BufferedReader(new InputStreamReader(url.openConnection().getInputStream(), "utf-8")); + String line = null; + StringBuffer result = new StringBuffer(); + while ((line = reader.readLine()) != null) { + result.append(line); + } + reader.close(); + Map map = JSON.parseObject(result.toString(), Map.class); + List> data = (List) map.get("data"); + return data.get(0).get("location"); + } catch (Exception e) { + return ""; + } + } + + /** + * 获取访问设备 + * + * @param request 请求 + * @return {@link UserAgent} 访问设备 + */ + public static UserAgent getUserAgent(HttpServletRequest request){ + return UserAgent.parseUserAgentString(request.getHeader("User-Agent")); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/blog/PageUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/blog/PageUtils.java new file mode 100644 index 0000000..6c3015b --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/blog/PageUtils.java @@ -0,0 +1,47 @@ +package com.zhi.common.utils.blog; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; + +import java.util.Objects; + +/** + * 分页工具类 + * + * @author yezhqiu + * @date 2021/07/18 + * @since 1.0.0 + **/ +public class PageUtils { + + private static final ThreadLocal> PAGE_HOLDER = new ThreadLocal<>(); + + public static void setCurrentPage(Page page) { + PAGE_HOLDER.set(page); + } + + public static Page getPage() { + Page page = PAGE_HOLDER.get(); + if (Objects.isNull(page)) { + setCurrentPage(new Page<>()); + } + return PAGE_HOLDER.get(); + } + + public static Long getCurrent() { + return getPage().getCurrent(); + } + + public static Long getSize() { + return getPage().getSize(); + } + + + public static Long getLimitCurrent() { + return (getCurrent() - 1) * getSize(); + } + + public static void remove() { + PAGE_HOLDER.remove(); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/blog/SensitiveUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/blog/SensitiveUtils.java new file mode 100644 index 0000000..4228f99 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/blog/SensitiveUtils.java @@ -0,0 +1,210 @@ +package com.zhi.common.utils.blog; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import lombok.extern.log4j.Log4j2; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * 敏感词过滤工具类(需要在resource下放置敏感词文件) + * + * @author yezhqiu + * @date 2021/06/13 + * @since 1.0.0 + **/ +@Log4j2 +@Component +public class SensitiveUtils { + + /** + * 敏感词文件 + */ + private static final String SENSITIVE_WORD = "sensitive-words.txt"; + + /** + * 替换符 + */ + private static final String REPLACEMENT = "***"; + + /** + * 根节点 + */ + private static final TrieNode ROOT_NODE = new TrieNode(); + + @PostConstruct + public void init() { + try ( + InputStream is = this.getClass().getClassLoader().getResourceAsStream(SENSITIVE_WORD); + BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is))) + ) { + String keyword; + while ((keyword = reader.readLine()) != null) { + // 添加到前缀树 + this.addKeyword(keyword); + } + } catch (Exception e) { + log.warn("加载敏感词文件失败: " + e.getMessage()); + } + } + + /** + * 将一个敏感词添加到前缀树中 + * + * @param keyword 敏感词 + */ + private void addKeyword(String keyword) { + TrieNode tempNode = ROOT_NODE; + for (int i = 0; i < keyword.length(); i++) { + char c = keyword.charAt(i); + TrieNode subNode = tempNode.getSubNode(c); + + if (subNode == null) { + // 初始化子节点 + subNode = new TrieNode(); + tempNode.addSubNode(c, subNode); + } + + // 指向子节点,进入下一轮循环 + tempNode = subNode; + + // 设置结束标识 + if (i == keyword.length() - 1) { + tempNode.setKeywordEnd(true); + } + } + } + + /** + * 过滤敏感词 + * + * @param text 待过滤的文本 + * @return 过滤后的文本 + */ + public static String filter(String text) { + if (StringUtils.isBlank(text)) { + return null; + } + // 指针1 + TrieNode tempNode = ROOT_NODE; + // 指针2 + int begin = 0; + // 指针3 + int position = 0; + // 结果 + StringBuilder sb = new StringBuilder(); + + while (position < text.length()) { + char c = text.charAt(position); + + // 跳过符号 + if (isSymbol(c)) { + // 若指针1处于根节点,将此符号计入结果,让指针2向下走一步 + if (tempNode == ROOT_NODE) { + sb.append(c); + begin++; + } + // 无论符号在开头或中间,指针3都向下走一步 + position++; + continue; + } + + // 检查下级节点 + tempNode = tempNode.getSubNode(c); + if (tempNode == null) { + // 以begin开头的字符串不是敏感词 + sb.append(text.charAt(begin)); + // 进入下一个位置 + position = ++begin; + // 重新指向根节点 + tempNode = ROOT_NODE; + } else if (tempNode.isKeywordEnd()) { + // 发现敏感词,将begin~position字符串替换掉 + sb.append(REPLACEMENT); + // 进入下一个位置 + begin = ++position; + // 重新指向根节点 + tempNode = ROOT_NODE; + } else { + // 检查下一个字符 + position++; + } + } + + // 将最后一批字符计入结果 + sb.append(text.substring(begin)); + + return sb.toString(); + } + + /** + * 判断是否为符号 + * + * @param c 字符 + * @return 判断 + */ + private static boolean isSymbol(Character c) { + // 0x2E80~0x9FFF 是东亚文字范围 + return !isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF); + } + + public static boolean isAsciiAlpha(char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + public static boolean isAsciiAlphaUpper(char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + public static boolean isAsciiAlphaLower(char ch) { + return ch >= 'a' && ch <= 'z'; + } + + public static boolean isAsciiNumeric(char ch) { + return ch >= '0' && ch <= '9'; + } + + public static boolean isAsciiAlphanumeric(char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + * 前缀树 + */ + private static class TrieNode { + + // 关键词结束标识 + private boolean isKeywordEnd = false; + + // 子节点(key是下级字符,value是下级节点) + private final Map subNodes = new HashMap<>(); + + public boolean isKeywordEnd() { + return isKeywordEnd; + } + + public void setKeywordEnd(boolean keywordEnd) { + isKeywordEnd = keywordEnd; + } + + // 添加子节点 + public void addSubNode(Character c, TrieNode node) { + subNodes.put(c, node); + } + + // 获取子节点 + public TrieNode getSubNode(Character c) { + return subNodes.get(c); + } + + } + +} + + diff --git a/zhi-common/src/main/java/com/zhi/common/utils/email/MailUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/email/MailUtils.java new file mode 100644 index 0000000..9aa3de7 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/email/MailUtils.java @@ -0,0 +1,468 @@ +package com.zhi.common.utils.email; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.mail.*; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.mail.Authenticator; +import javax.mail.Session; +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +/** + * 邮件工具类 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MailUtils { + + private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class); + + /** + * 获取邮件发送实例 + */ + public static MailAccount getMailAccount() { + return ACCOUNT; + } + + /** + * 获取邮件发送实例 (自定义发送人以及授权码) + * + * @param user 发送人 + * @param pass 授权码 + */ + public static MailAccount getMailAccount(String from, String user, String pass) { + ACCOUNT.setFrom(StringUtils.blankToDefault(from, ACCOUNT.getFrom())); + ACCOUNT.setUser(StringUtils.blankToDefault(user, ACCOUNT.getUser())); + ACCOUNT.setPass(StringUtils.blankToDefault(pass, ACCOUNT.getPass())); + return ACCOUNT; + } + + /** + * 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendText(String to, String subject, String content, File... files) { + return send(to, subject, content, false, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, File... files) { + return send(to, subject, content, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送文本邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + */ + public static String sendText(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, false, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, File... files) { + return send(tos, subject, content, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(String to, String subject, String content, Map imageMap, File... files) { + return send(to, subject, content, imageMap, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送单个或多个收件人
+ * 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * + * @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param cc 抄送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param bcc 密送人,可以使用逗号“,”分隔,也可以通过分号“;”分隔 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(String to, String cc, String bcc, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送HTML邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String sendHtml(Collection tos, String subject, String content, Map imageMap, File... files) { + return send(tos, subject, content, imageMap, true, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + */ + public static String send(Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(tos, null, null, subject, content, imageMap, isHtml, files); + } + + /** + * 使用配置文件中设置的账户发送邮件,发送给多人 + * + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML + * @param files 附件列表 + * @return message-id + * @since 4.0.3 + */ + public static String send(Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + // ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件认证对象 + * @param to 收件人,多个收件人逗号或者分号隔开 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 3.2.0 + */ + public static String send(MailAccount mailAccount, String to, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, String subject, String content, Map imageMap, boolean isHtml, File... files) { + return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files); + } + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + public static String send(MailAccount mailAccount, Collection tos, Collection ccs, Collection bccs, String subject, String content, Map imageMap, + boolean isHtml, File... files) { + return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files); + } + + /** + * 根据配置文件,获取邮件客户端会话 + * + * @param mailAccount 邮件账户配置 + * @param isSingleton 是否单例(全局共享会话) + * @return {@link Session} + * @since 5.5.7 + */ + public static Session getSession(MailAccount mailAccount, boolean isSingleton) { + Authenticator authenticator = null; + if (mailAccount.isAuth()) { + authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass()); + } + + return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) // + : Session.getInstance(mailAccount.getSmtpProps(), authenticator); + } + + // ------------------------------------------------------------------------------------------------------------------------ Private method start + + /** + * 发送邮件给多人 + * + * @param mailAccount 邮件帐户信息 + * @param useGlobalSession 是否全局共享Session + * @param tos 收件人列表 + * @param ccs 抄送人列表,可以为null或空 + * @param bccs 密送人列表,可以为null或空 + * @param subject 标题 + * @param content 正文 + * @param imageMap 图片与占位符,占位符格式为cid:${cid} + * @param isHtml 是否为HTML格式 + * @param files 附件列表 + * @return message-id + * @since 4.6.3 + */ + private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content, + Map imageMap, boolean isHtml, File... files) { + final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession); + + // 可选抄送人 + if (CollUtil.isNotEmpty(ccs)) { + mail.setCcs(ccs.toArray(new String[0])); + } + // 可选密送人 + if (CollUtil.isNotEmpty(bccs)) { + mail.setBccs(bccs.toArray(new String[0])); + } + + mail.setTos(tos.toArray(new String[0])); + mail.setTitle(subject); + mail.setContent(content); + mail.setHtml(isHtml); + mail.setFiles(files); + + // 图片 + if (MapUtil.isNotEmpty(imageMap)) { + for (Map.Entry entry : imageMap.entrySet()) { + mail.addImage(entry.getKey(), entry.getValue()); + // 关闭流 + IoUtil.close(entry.getValue()); + } + } + + return mail.send(); + } + + /** + * 将多个联系人转为列表,分隔符为逗号或者分号 + * + * @param addresses 多个联系人,如果为空返回null + * @return 联系人列表 + */ + private static List splitAddress(String addresses) { + if (StrUtil.isBlank(addresses)) { + return null; + } + + List result; + if (StrUtil.contains(addresses, CharUtil.COMMA)) { + result = StrUtil.splitTrim(addresses, CharUtil.COMMA); + } else if (StrUtil.contains(addresses, ';')) { + result = StrUtil.splitTrim(addresses, ';'); + } else { + result = CollUtil.newArrayList(addresses); + } + return result; + } + // ------------------------------------------------------------------------------------------------------------------------ Private method end + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/file/FileUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/file/FileUtils.java new file mode 100644 index 0000000..3a1f9aa --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/file/FileUtils.java @@ -0,0 +1,52 @@ +package com.zhi.common.utils.file; + +import cn.hutool.core.io.FileUtil; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.servlet.http.HttpServletResponse; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * 文件处理工具类 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class FileUtils extends FileUtil { + + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException { + String percentEncodedFileName = percentEncode(realFileName); + + StringBuilder contentDispositionValue = new StringBuilder(); + contentDispositionValue.append("attachment; filename=") + .append(percentEncodedFileName) + .append(";") + .append("filename*=") + .append("utf-8''") + .append(percentEncodedFileName); + + response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); + response.setHeader("Content-disposition", contentDispositionValue.toString()); + response.setHeader("download-filename", percentEncodedFileName); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) throws UnsupportedEncodingException { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); + return encode.replaceAll("\\+", "%20"); + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/file/MimeTypeUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/file/MimeTypeUtils.java new file mode 100644 index 0000000..e7ba0b5 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/file/MimeTypeUtils.java @@ -0,0 +1,40 @@ +package com.zhi.common.utils.file; + +/** + * 媒体类型工具类 + * + * @author ruoyi + */ +public class MimeTypeUtils { + public static final String IMAGE_PNG = "image/png"; + + public static final String IMAGE_JPG = "image/jpg"; + + public static final String IMAGE_JPEG = "image/jpeg"; + + public static final String IMAGE_BMP = "image/bmp"; + + public static final String IMAGE_GIF = "image/gif"; + + public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"}; + + public static final String[] FLASH_EXTENSION = {"swf", "flv"}; + + public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb"}; + + public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"}; + + public static final String[] DEFAULT_ALLOWED_EXTENSION = { + // 图片 + "bmp", "gif", "jpg", "jpeg", "png", + // word excel powerpoint + "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + // 压缩文件 + "rar", "zip", "gz", "bz2", + // 视频格式 + "mp4", "avi", "rmvb", + // pdf + "pdf"}; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/ip/AddressUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/ip/AddressUtils.java new file mode 100644 index 0000000..fe3e52b --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/ip/AddressUtils.java @@ -0,0 +1,60 @@ +package com.zhi.common.utils.ip; + +import cn.hutool.core.lang.Dict; +import cn.hutool.core.net.NetUtil; +import cn.hutool.http.HtmlUtil; +import cn.hutool.http.HttpUtil; +import com.zhi.common.config.RuoYiConfig; +import com.zhi.common.constant.Constants; +import com.zhi.common.utils.JsonUtils; +import com.zhi.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * 获取地址类 + * + * @author Lion Li + */ +@Slf4j +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class AddressUtils { + + // IP地址查询 + public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; + + // 未知地址 + public static final String UNKNOWN = "XX XX"; + + public static String getRealAddressByIP(String ip) { + String address = UNKNOWN; + if (StringUtils.isBlank(ip)) { + return address; + } + // 内网不查询 + ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip); + if (NetUtil.isInnerIP(ip)) { + return "内网IP"; + } + if (RuoYiConfig.isAddressEnabled()) { + try { + String rspStr = HttpUtil.createGet(IP_URL) + .body("ip=" + ip + "&json=true", Constants.GBK) + .execute() + .body(); + if (StringUtils.isEmpty(rspStr)) { + log.error("获取地理位置异常 {}", ip); + return UNKNOWN; + } + Dict obj = JsonUtils.parseMap(rspStr); + String region = obj.getStr("pro"); + String city = obj.getStr("city"); + return String.format("%s %s", region, city); + } catch (Exception e) { + log.error("获取地理位置异常 {}", ip); + } + } + return UNKNOWN; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/ip/WebsocketUtil.java b/zhi-common/src/main/java/com/zhi/common/utils/ip/WebsocketUtil.java new file mode 100644 index 0000000..047413a --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/ip/WebsocketUtil.java @@ -0,0 +1,49 @@ +package com.zhi.common.utils.ip; + +import java.lang.reflect.Field; +import java.net.InetSocketAddress; +import javax.websocket.RemoteEndpoint.Async; +import javax.websocket.Session; + +public class WebsocketUtil { + + public static InetSocketAddress getRemoteAddress(Session session) { + if (session == null) { + return null; + } + Async async = session.getAsyncRemote(); + + //在Tomcat 8.0.x版本有效 +// InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async,"base#sos#socketWrapper#socket#sc#remoteAddress"); + //在Tomcat 8.5以上版本有效 + InetSocketAddress addr = (InetSocketAddress) getFieldInstance(async,"base#socketWrapper#socket#sc#remoteAddress"); + return addr; + } + + private static Object getFieldInstance(Object obj, String fieldPath) { + String fields[] = fieldPath.split("#"); + for (String field : fields) { + obj = getField(obj, obj.getClass(), field); + if (obj == null) { + return null; + } + } + + return obj; + } + + private static Object getField(Object obj, Class clazz, String fieldName) { + for (; clazz != Object.class; clazz = clazz.getSuperclass()) { + try { + Field field; + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(obj); + } catch (Exception e) { + } + } + + return null; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/poi/ExcelUtil.java b/zhi-common/src/main/java/com/zhi/common/utils/poi/ExcelUtil.java new file mode 100644 index 0000000..a8142d6 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/poi/ExcelUtil.java @@ -0,0 +1,266 @@ +package com.zhi.common.utils.poi; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import cn.hutool.core.util.IdUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.builder.ExcelWriterSheetBuilder; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.zhi.common.convert.ExcelBigNumberConvert; +import com.zhi.common.excel.CellMergeStrategy; +import com.zhi.common.excel.DefaultExcelListener; +import com.zhi.common.excel.ExcelListener; +import com.zhi.common.excel.ExcelResult; +import com.zhi.common.utils.StringUtils; +import com.zhi.common.utils.file.FileUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * Excel相关处理 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ExcelUtil { + + /** + * 同步导入(适用于小数据量) + * + * @param is 输入流 + * @return 转换后集合 + */ + public static List importExcel(InputStream is, Class clazz) { + return EasyExcel.read(is).head(clazz).autoCloseStream(false).sheet().doReadSync(); + } + + + /** + * 使用校验监听器 异步导入 同步返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param isValidate 是否 Validator 检验 默认为是 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, boolean isValidate) { + DefaultExcelListener listener = new DefaultExcelListener<>(isValidate); + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 使用自定义监听器 异步导入 自定义返回 + * + * @param is 输入流 + * @param clazz 对象类型 + * @param listener 自定义监听器 + * @return 转换后集合 + */ + public static ExcelResult importExcel(InputStream is, Class clazz, ExcelListener listener) { + EasyExcel.read(is, clazz, listener).sheet().doRead(); + return listener.getExcelResult(); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response) { + exportExcel(list, sheetName, clazz, false, response); + } + + /** + * 导出excel + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @param clazz 实体类 + * @param merge 是否合并单元格 + * @param response 响应体 + */ + public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response) { + try { + resetResponse(sheetName, response); + ServletOutputStream os = response.getOutputStream(); + ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz) + .autoCloseStream(false) + // 自动适配 + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .sheet(sheetName); + if (merge) { + // 合并处理器 + builder.registerWriteHandler(new CellMergeStrategy(list, true)); + } + builder.doWrite(list); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 单表多数据模板导出 模板格式为 {.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + */ + public static void exportTemplate(List data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + // 单表多数据导出 模板格式为 {.属性} + for (Object d : data) { + excelWriter.fill(d, writeSheet); + } + excelWriter.finish(); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 多表多数据模板导出 模板格式为 {key.属性} + * + * @param filename 文件名 + * @param templatePath 模板路径 resource 目录下的路径包括模板文件名 + * 例如: excel/temp.xlsx + * 重点: 模板文件必须放置到启动类对应的 resource 目录下 + * @param data 模板需要的数据 + */ + public static void exportTemplateMultiList(Map data, String filename, String templatePath, HttpServletResponse response) { + try { + resetResponse(filename, response); + ClassPathResource templateResource = new ClassPathResource(templatePath); + ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()) + .withTemplate(templateResource.getStream()) + .autoCloseStream(false) + // 大数值自动转换 防止失真 + .registerConverter(new ExcelBigNumberConvert()) + .build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + if (CollUtil.isEmpty(data)) { + throw new IllegalArgumentException("数据为空"); + } + for (Map.Entry map : data.entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } + } + excelWriter.finish(); + } catch (IOException e) { + throw new RuntimeException("导出Excel异常"); + } + } + + /** + * 重置响应体 + */ + private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException { + String filename = encodingFilename(sheetName); + FileUtils.setAttachmentResponseHeader(response, filename); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8"); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + 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 (StringUtils.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 StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + */ + 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 (StringUtils.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 StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 编码文件名 + */ + public static String encodingFilename(String filename) { + return IdUtil.fastSimpleUUID() + "_" + filename + ".xlsx"; + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/redis/CacheUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/redis/CacheUtils.java new file mode 100644 index 0000000..8eff2c8 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/redis/CacheUtils.java @@ -0,0 +1,75 @@ +package com.zhi.common.utils.redis; + +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.RMap; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; + +import java.util.Set; + +/** + * 缓存操作工具类 {@link } + * + * @author Michelle.Chung + * @date 2022/8/13 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings(value = {"unchecked"}) +public class CacheUtils { + + private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class); + + /** + * 获取缓存组内所有的KEY + * + * @param cacheNames 缓存组名称 + */ + public static Set keys(String cacheNames) { + RMap rmap = (RMap) CACHE_MANAGER.getCache(cacheNames).getNativeCache(); + return rmap.keySet(); + } + + /** + * 获取缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + */ + public static T get(String cacheNames, Object key) { + Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key); + return wrapper != null ? (T) wrapper.get() : null; + } + + /** + * 保存缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + * @param value 缓存值 + */ + public static void put(String cacheNames, Object key, Object value) { + CACHE_MANAGER.getCache(cacheNames).put(key, value); + } + + /** + * 删除缓存值 + * + * @param cacheNames 缓存组名称 + * @param key 缓存key + */ + public static void evict(String cacheNames, Object key) { + CACHE_MANAGER.getCache(cacheNames).evict(key); + } + + /** + * 清空缓存值 + * + * @param cacheNames 缓存组名称 + */ + public static void clear(String cacheNames) { + CACHE_MANAGER.getCache(cacheNames).clear(); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/redis/QueueUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/redis/QueueUtils.java new file mode 100644 index 0000000..5fd2e05 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/redis/QueueUtils.java @@ -0,0 +1,180 @@ +package com.zhi.common.utils.redis; + +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.*; + +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * 分布式队列工具 + * 轻量级队列 重量级数据量 请使用 MQ + * 要求 redis 5.X 以上 + * + * @author Lion Li + * @version 3.6.0 新增 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class QueueUtils { + + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + + + /** + * 获取客户端实例 + */ + public static RedissonClient getClient() { + return CLIENT; + } + + /** + * 添加普通队列数据 + * + * @param queueName 队列名 + * @param data 数据 + */ + public static boolean addQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.offer(data); + } + + /** + * 通用获取一个队列数据 没有数据返回 null(不支持延迟队列) + * + * @param queueName 队列名 + */ + public static T getQueueObject(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.poll(); + } + + /** + * 通用删除队列数据(不支持延迟队列) + */ + public static boolean removeQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.remove(data); + } + + /** + * 通用销毁队列 所有阻塞监听 报错(不支持延迟队列) + */ + public static boolean destroyQueue(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + return queue.delete(); + } + + /** + * 添加延迟队列数据 默认毫秒 + * + * @param queueName 队列名 + * @param data 数据 + * @param time 延迟时间 + */ + public static void addDelayedQueueObject(String queueName, T data, long time) { + addDelayedQueueObject(queueName, data, time, TimeUnit.MILLISECONDS); + } + + /** + * 添加延迟队列数据 + * + * @param queueName 队列名 + * @param data 数据 + * @param time 延迟时间 + * @param timeUnit 单位 + */ + public static void addDelayedQueueObject(String queueName, T data, long time, TimeUnit timeUnit) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + delayedQueue.offer(data, time, timeUnit); + } + + /** + * 获取一个延迟队列数据 没有数据返回 null + * + * @param queueName 队列名 + */ + public static T getDelayedQueueObject(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + return delayedQueue.poll(); + } + + /** + * 删除延迟队列数据 + */ + public static boolean removeDelayedQueueObject(String queueName, T data) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + return delayedQueue.remove(data); + } + + /** + * 销毁延迟队列 所有阻塞监听 报错 + */ + public static void destroyDelayedQueue(String queueName) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + RDelayedQueue delayedQueue = CLIENT.getDelayedQueue(queue); + delayedQueue.destroy(); + } + + /** + * 添加优先队列数据 + * + * @param queueName 队列名 + * @param data 数据 + */ + public static boolean addPriorityQueueObject(String queueName, T data) { + RPriorityBlockingQueue priorityBlockingQueue = CLIENT.getPriorityBlockingQueue(queueName); + return priorityBlockingQueue.offer(data); + } + + /** + * 尝试设置 有界队列 容量 用于限制数量 + * + * @param queueName 队列名 + * @param capacity 容量 + */ + public static boolean trySetBoundedQueueCapacity(String queueName, int capacity) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + return boundedBlockingQueue.trySetCapacity(capacity); + } + + /** + * 尝试设置 有界队列 容量 用于限制数量 + * + * @param queueName 队列名 + * @param capacity 容量 + * @param destroy 已存在是否销毁 + */ + public static boolean trySetBoundedQueueCapacity(String queueName, int capacity, boolean destroy) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + if (boundedBlockingQueue.isExists() && destroy) { + destroyQueue(queueName); + } + return boundedBlockingQueue.trySetCapacity(capacity); + } + + /** + * 添加有界队列数据 + * + * @param queueName 队列名 + * @param data 数据 + * @return 添加成功 true 已达到界限 false + */ + public static boolean addBoundedQueueObject(String queueName, T data) { + RBoundedBlockingQueue boundedBlockingQueue = CLIENT.getBoundedBlockingQueue(queueName); + return boundedBlockingQueue.offer(data); + } + + /** + * 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 等) + */ + public static void subscribeBlockingQueue(String queueName, Consumer consumer) { + RBlockingQueue queue = CLIENT.getBlockingQueue(queueName); + queue.subscribeOnElements(consumer); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/redis/RedisUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/redis/RedisUtils.java new file mode 100644 index 0000000..1f1b61e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/redis/RedisUtils.java @@ -0,0 +1,462 @@ +package com.zhi.common.utils.redis; + +import com.zhi.common.utils.spring.SpringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.redisson.api.*; +import org.redisson.config.Config; + +import java.time.Duration; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * redis 工具类 + * + * @author Lion Li + * @version 3.1.0 新增 + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +@SuppressWarnings(value = {"unchecked", "rawtypes"}) +public class RedisUtils { + + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + + public static NameMapper getNameMapper() { + Config config = CLIENT.getConfig(); + if (config.isClusterConfig()) { + return config.useClusterServers().getNameMapper(); + } + return config.useSingleServer().getNameMapper(); + } + + /** + * 限流 + * + * @param key 限流key + * @param rateType 限流类型 + * @param rate 速率 + * @param rateInterval 速率间隔 + * @return -1 表示失败 + */ + public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) { + RRateLimiter rateLimiter = CLIENT.getRateLimiter(key); + rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS); + if (rateLimiter.tryAcquire()) { + return rateLimiter.availablePermits(); + } else { + return -1L; + } + } + + /** + * 获取客户端实例 + */ + public static RedissonClient getClient() { + return CLIENT; + } + + /** + * 发布通道消息 + * + * @param channelKey 通道key + * @param msg 发送数据 + * @param consumer 自定义处理 + */ + public static void publish(String channelKey, T msg, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + consumer.accept(msg); + } + + public static void publish(String channelKey, T msg) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + } + + /** + * 订阅通道接收消息 + * + * @param channelKey 通道key + * @param clazz 消息类型 + * @param consumer 自定义处理 + */ + public static void subscribe(String channelKey, Class clazz, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + */ + public static void setCacheObject(final String key, final T value) { + setCacheObject(key, value, false); + } + + /** + * 缓存基本的对象,保留当前对象 TTL 有效期 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param isSaveTtl 是否保留TTL有效期(例如: set之前ttl剩余90 set之后还是为90) + * @since Redis 6.X 以上使用 setAndKeepTTL 兼容 5.X 方案 + */ + public static void setCacheObject(final String key, final T value, final boolean isSaveTtl) { + RBucket bucket = CLIENT.getBucket(key); + if (isSaveTtl) { + try { + bucket.setAndKeepTTL(value); + } catch (Exception e) { + long timeToLive = bucket.remainTimeToLive(); + setCacheObject(key, value, Duration.ofMillis(timeToLive)); + } + } else { + bucket.set(value); + } + } + + /** + * 缓存基本的对象,Integer、String、实体类等 + * + * @param key 缓存的键值 + * @param value 缓存的值 + * @param duration 时间 + */ + public static void setCacheObject(final String key, final T value, final Duration duration) { + RBatch batch = CLIENT.createBatch(); + RBucketAsync bucket = batch.getBucket(key); + bucket.setAsync(value); + bucket.expireAsync(duration); + batch.execute(); + } + + /** + * 注册对象监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addObjectListener(final String key, final ObjectListener listener) { + RBucket result = CLIENT.getBucket(key); + result.addListener(listener); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param timeout 超时时间 + * @return true=设置成功;false=设置失败 + */ + public static boolean expire(final String key, final long timeout) { + return expire(key, Duration.ofSeconds(timeout)); + } + + /** + * 设置有效时间 + * + * @param key Redis键 + * @param duration 超时时间 + * @return true=设置成功;false=设置失败 + */ + public static boolean expire(final String key, final Duration duration) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.expire(duration); + } + + /** + * 获得缓存的基本对象。 + * + * @param key 缓存键值 + * @return 缓存键值对应的数据 + */ + public static T getCacheObject(final String key) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.get(); + } + + /** + * 获得key剩余存活时间 + * + * @param key 缓存键值 + * @return 剩余存活时间 + */ + public static long getTimeToLive(final String key) { + RBucket rBucket = CLIENT.getBucket(key); + return rBucket.remainTimeToLive(); + } + + /** + * 删除单个对象 + * + * @param key 缓存的键值 + */ + public static boolean deleteObject(final String key) { + return CLIENT.getBucket(key).delete(); + } + + /** + * 删除集合对象 + * + * @param collection 多个对象 + */ + public static void deleteObject(final Collection collection) { + RBatch batch = CLIENT.createBatch(); + collection.forEach(t -> { + batch.getBucket(t.toString()).deleteAsync(); + }); + batch.execute(); + } + + /** + * 缓存List数据 + * + * @param key 缓存的键值 + * @param dataList 待缓存的List数据 + * @return 缓存的对象 + */ + public static boolean setCacheList(final String key, final List dataList) { + RList rList = CLIENT.getList(key); + return rList.addAll(dataList); + } + + /** + * 注册List监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addListListener(final String key, final ObjectListener listener) { + RList rList = CLIENT.getList(key); + rList.addListener(listener); + } + + /** + * 获得缓存的list对象 + * + * @param key 缓存的键值 + * @return 缓存键值对应的数据 + */ + public static List getCacheList(final String key) { + RList rList = CLIENT.getList(key); + return rList.readAll(); + } + + /** + * 缓存Set + * + * @param key 缓存键值 + * @param dataSet 缓存的数据 + * @return 缓存数据的对象 + */ + public static boolean setCacheSet(final String key, final Set dataSet) { + RSet rSet = CLIENT.getSet(key); + return rSet.addAll(dataSet); + } + + /** + * 注册Set监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addSetListener(final String key, final ObjectListener listener) { + RSet rSet = CLIENT.getSet(key); + rSet.addListener(listener); + } + + /** + * 获得缓存的set + * + * @param key 缓存的key + * @return set对象 + */ + public static Set getCacheSet(final String key) { + RSet rSet = CLIENT.getSet(key); + return rSet.readAll(); + } + + /** + * 缓存Map + * + * @param key 缓存的键值 + * @param dataMap 缓存的数据 + */ + public static void setCacheMap(final String key, final Map dataMap) { + if (dataMap != null) { + RMap rMap = CLIENT.getMap(key); + rMap.putAll(dataMap); + } + } + + /** + * 注册Map监听器 + *

+ * key 监听器需开启 `notify-keyspace-events` 等 redis 相关配置 + * + * @param key 缓存的键值 + * @param listener 监听器配置 + */ + public static void addMapListener(final String key, final ObjectListener listener) { + RMap rMap = CLIENT.getMap(key); + rMap.addListener(listener); + } + + /** + * 获得缓存的Map + * + * @param key 缓存的键值 + * @return map对象 + */ + public static Map getCacheMap(final String key) { + RMap rMap = CLIENT.getMap(key); + return rMap.getAll(rMap.keySet()); + } + + /** + * 获得缓存Map的key列表 + * + * @param key 缓存的键值 + * @return key列表 + */ + public static Set getCacheMapKeySet(final String key) { + RMap rMap = CLIENT.getMap(key); + return rMap.keySet(); + } + + /** + * 往Hash中存入数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @param value 值 + */ + public static void setCacheMapValue(final String key, final String hKey, final T value) { + RMap rMap = CLIENT.getMap(key); + rMap.put(hKey, value); + } + + /** + * 获取Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public static T getCacheMapValue(final String key, final String hKey) { + RMap rMap = CLIENT.getMap(key); + return rMap.get(hKey); + } + + /** + * 删除Hash中的数据 + * + * @param key Redis键 + * @param hKey Hash键 + * @return Hash中的对象 + */ + public static T delCacheMapValue(final String key, final String hKey) { + RMap rMap = CLIENT.getMap(key); + return rMap.remove(hKey); + } + + /** + * 获取多个Hash中的数据 + * + * @param key Redis键 + * @param hKeys Hash键集合 + * @return Hash对象集合 + */ + public static Map getMultiCacheMapValue(final String key, final Set hKeys) { + RMap rMap = CLIENT.getMap(key); + return rMap.getAll(hKeys); + } + + /** + * 设置原子值 + * + * @param key Redis键 + * @param value 值 + */ + public static void setAtomicValue(String key, long value) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + atomic.set(value); + } + + /** + * 获取原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long getAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.get(); + } + + /** + * 递增原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long incrAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.incrementAndGet(); + } + + /** + * 递减原子值 + * + * @param key Redis键 + * @return 当前值 + */ + public static long decrAtomicValue(String key) { + RAtomicLong atomic = CLIENT.getAtomicLong(key); + return atomic.decrementAndGet(); + } + + /** + * 获得缓存的基本对象列表 + * + * @param pattern 字符串前缀 + * @return 对象列表 + */ + public static Collection keys(final String pattern) { + Stream stream = CLIENT.getKeys().getKeysStreamByPattern(getNameMapper().map(pattern)); + return stream.map(key -> getNameMapper().unmap(key)).collect(Collectors.toList()); + } + + /** + * 删除缓存的基本对象列表 + * + * @param pattern 字符串前缀 + */ + public static void deleteKeys(final String pattern) { + CLIENT.getKeys().deleteByPattern(getNameMapper().map(pattern)); + } + + /** + * 检查redis中是否存在key + * + * @param key 键 + */ + public static Boolean hasKey(String key) { + RKeys rKeys = CLIENT.getKeys(); + return rKeys.countExists(getNameMapper().map(key)) > 0; + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/reflect/ReflectUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/reflect/ReflectUtils.java new file mode 100644 index 0000000..7432474 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/reflect/ReflectUtils.java @@ -0,0 +1,56 @@ +package com.zhi.common.utils.reflect; + +import cn.hutool.core.util.ReflectUtil; +import com.zhi.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.lang.reflect.Method; + +/** + * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数. + * + * @author Lion Li + */ +@SuppressWarnings("rawtypes") +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ReflectUtils extends ReflectUtil { + + private static final String SETTER_PREFIX = "set"; + + private static final String GETTER_PREFIX = "get"; + + /** + * 调用Getter方法. + * 支持多级,如:对象名.对象名.方法 + */ + @SuppressWarnings("unchecked") + public static E invokeGetter(Object obj, String propertyName) { + Object object = obj; + for (String name : StringUtils.split(propertyName, ".")) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); + object = invoke(object, getterMethodName); + } + return (E) object; + } + + /** + * 调用Setter方法, 仅匹配方法名。 + * 支持多级,如:对象名.对象名.方法 + */ + public static void invokeSetter(Object obj, String propertyName, E value) { + Object object = obj; + String[] names = StringUtils.split(propertyName, "."); + for (int i = 0; i < names.length; i++) { + if (i < names.length - 1) { + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); + object = invoke(object, getterMethodName); + } else { + String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); + Method method = getMethodByName(object.getClass(), setterMethodName); + invoke(object, method, value); + } + } + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/spring/SpringUtils.java b/zhi-common/src/main/java/com/zhi/common/utils/spring/SpringUtils.java new file mode 100644 index 0000000..a5eedc1 --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/spring/SpringUtils.java @@ -0,0 +1,65 @@ +package com.zhi.common.utils.spring; + +import cn.hutool.extra.spring.SpringUtil; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.stereotype.Component; + +/** + * spring工具类 + * + * @author Lion Li + */ +@Component +public final class SpringUtils extends SpringUtil { + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) { + return getBeanFactory().containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 + * 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + return getBeanFactory().getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) { + return (T) AopContext.currentProxy(); + } + +} diff --git a/zhi-common/src/main/java/com/zhi/common/utils/sql/SqlUtil.java b/zhi-common/src/main/java/com/zhi/common/utils/sql/SqlUtil.java new file mode 100644 index 0000000..e6ecabe --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/utils/sql/SqlUtil.java @@ -0,0 +1,57 @@ +package com.zhi.common.utils.sql; + +import com.zhi.common.exception.UtilException; +import com.zhi.common.utils.StringUtils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +/** + * sql操作工具类 + * + * @author ruoyi + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class SqlUtil { + + /** + * 定义常用的 sql关键字 + */ + public static final String SQL_REGEX = "select |insert |delete |update |drop |count |exec |chr |mid |master |truncate |char |and |declare "; + + /** + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) + */ + public static final String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; + + /** + * 检查字符,防止注入绕过 + */ + public static String escapeOrderBySql(String value) { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { + throw new UtilException("参数不符合规范,不能进行查询"); + } + return value; + } + + /** + * 验证 order by 语法是否符合规范 + */ + public static boolean isValidOrderBySql(String value) { + return value.matches(SQL_PATTERN); + } + + /** + * SQL关键字检查 + */ + public static void filterKeyword(String value) { + if (StringUtils.isEmpty(value)) { + return; + } + String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|"); + for (String sqlKeyword : sqlKeywords) { + if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1) { + throw new UtilException("参数存在SQL注入风险"); + } + } + } +} diff --git a/zhi-common/src/main/java/com/zhi/common/xss/Xss.java b/zhi-common/src/main/java/com/zhi/common/xss/Xss.java new file mode 100644 index 0000000..7ebad6e --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/xss/Xss.java @@ -0,0 +1,26 @@ +package com.zhi.common.xss; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义xss校验注解 + * + * @author Lion Li + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER}) +@Constraint(validatedBy = {XssValidator.class}) +public @interface Xss { + + String message() default "不允许任何脚本运行"; + + Class[] groups() default {}; + + Class[] payload() default {}; + +} diff --git a/zhi-common/src/main/java/com/zhi/common/xss/XssValidator.java b/zhi-common/src/main/java/com/zhi/common/xss/XssValidator.java new file mode 100644 index 0000000..2e491ff --- /dev/null +++ b/zhi-common/src/main/java/com/zhi/common/xss/XssValidator.java @@ -0,0 +1,21 @@ +package com.zhi.common.xss; + +import cn.hutool.core.util.ReUtil; +import cn.hutool.http.HtmlUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * 自定义xss校验注解实现 + * + * @author Lion Li + */ +public class XssValidator implements ConstraintValidator { + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value); + } + +} diff --git a/zhi-demo/pom.xml b/zhi-demo/pom.xml new file mode 100644 index 0000000..a5c0f78 --- /dev/null +++ b/zhi-demo/pom.xml @@ -0,0 +1,44 @@ + + + + ruoyi-vue-plus + com.zhi + 4.4.0 + + 4.0.0 + + zhi-demo + + + demo模块 + + + + + + + com.zhi + zhi-common + + + + com.zhi + zhi-sms + + + + + + + + + + + + + + + + diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/MailController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/MailController.java new file mode 100644 index 0000000..4aa47e2 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/MailController.java @@ -0,0 +1,52 @@ +package com.zhi.demo.controller; + +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.email.MailUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.File; + + +/** + * 邮件发送案例 + * + * @author Michelle.Chung + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/mail") +public class MailController { + + /** + * 发送邮件 + * + * @param to 接收人 + * @param subject 标题 + * @param text 内容 + */ + @GetMapping("/sendSimpleMessage") + public R sendSimpleMessage(String to, String subject, String text) { + MailUtils.sendText(to, subject, text); + return R.ok(); + } + + /** + * 发送邮件(带附件) + * + * @param to 接收人 + * @param subject 标题 + * @param text 内容 + * @param filePath 附件路径 + */ + @GetMapping("/sendMessageWithAttachment") + public R sendMessageWithAttachment(String to, String subject, String text, String filePath) { + MailUtils.sendText(to, subject, text, new File(filePath)); + return R.ok(); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/RedisCacheController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisCacheController.java new file mode 100644 index 0000000..2992cf3 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisCacheController.java @@ -0,0 +1,95 @@ +package com.zhi.demo.controller; + +import com.zhi.common.constant.CacheNames; +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.redis.RedisUtils; +import lombok.RequiredArgsConstructor; +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; + +import java.time.Duration; + +/** + * spring-cache 演示案例 + * + * @author Lion Li + */ +// 类级别 缓存统一配置 +//@CacheConfig(cacheNames = CacheNames.DEMO_CACHE) +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/cache") +public class RedisCacheController { + + /** + * 测试 @Cacheable + *

+ * 表示这个方法有了缓存的功能,方法的返回值会被缓存下来 + * 下一次调用该方法前,会去检查是否缓存中已经有值 + * 如果有就直接返回,不调用方法 + * 如果没有,就调用方法,然后把结果缓存起来 + * 这个注解「一般用在查询方法上」 + *

+ * 重点说明: 缓存注解严谨与其他筛选数据功能一起使用 + * 例如: 数据权限注解 会造成 缓存击穿 与 数据不一致问题 + *

+ * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 + */ + @Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null") + @GetMapping("/test1") + public R test1(String key, String value) { + return R.ok("操作成功", value); + } + + /** + * 测试 @CachePut + *

+ * 加了@CachePut注解的方法,会把方法的返回值put到缓存里面缓存起来,供其它地方使用 + * 它「通常用在新增或者实时更新方法上」 + *

+ * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 + */ + @CachePut(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") + @GetMapping("/test2") + public R test2(String key, String value) { + return R.ok("操作成功", value); + } + + /** + * 测试 @CacheEvict + *

+ * 使用了CacheEvict注解的方法,会清空指定缓存 + * 「一般用在删除的方法上」 + *

+ * cacheNames 命名规则 查看 {@link CacheNames} 注释 支持多参数 + */ + @CacheEvict(cacheNames = CacheNames.DEMO_CACHE, key = "#key", condition = "#key != null") + @GetMapping("/test3") + public R test3(String key, String value) { + return R.ok("操作成功", value); + } + + /** + * 测试设置过期时间 + * 手动设置过期时间10秒 + * 11秒后获取 判断是否相等 + */ + @GetMapping("/test6") + public R test6(String key, String value) { + RedisUtils.setCacheObject(key, value); + boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10)); + System.out.println("***********" + flag); + try { + Thread.sleep(11 * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Object obj = RedisUtils.getCacheObject(key); + return R.ok(value.equals(obj)); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/RedisLockController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisLockController.java new file mode 100644 index 0000000..810a550 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisLockController.java @@ -0,0 +1,71 @@ +package com.zhi.demo.controller; + +import com.baomidou.lock.LockInfo; +import com.baomidou.lock.LockTemplate; +import com.baomidou.lock.annotation.Lock4j; +import com.baomidou.lock.executor.RedissonLockExecutor; +import com.zhi.common.core.domain.R; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalTime; + + +/** + * 测试分布式锁的样例 + * + * @author shenxinquan + */ +@Slf4j +@RestController +@RequestMapping("/demo/redisLock") +public class RedisLockController { + + @Autowired + private LockTemplate lockTemplate; + + /** + * 测试lock4j 注解 + */ + @Lock4j(keys = {"#key"}) + @GetMapping("/testLock4j") + public R testLock4j(String key, String value) { + System.out.println("start:" + key + ",time:" + LocalTime.now().toString()); + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("end :" + key + ",time:" + LocalTime.now().toString()); + return R.ok("操作成功", value); + } + + /** + * 测试lock4j 工具 + */ + @GetMapping("/testLock4jLockTemplate") + public R testLock4jLockTemplate(String key, String value) { + final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class); + if (null == lockInfo) { + throw new RuntimeException("业务处理中,请稍后再试"); + } + // 获取锁成功,处理业务 + try { + try { + Thread.sleep(8000); + } catch (InterruptedException e) { + // + } + System.out.println("执行简单方法1 , 当前线程:" + Thread.currentThread().getName()); + } finally { + //释放锁 + lockTemplate.releaseLock(lockInfo); + } + //结束 + return R.ok("操作成功", value); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/RedisPubSubController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisPubSubController.java new file mode 100644 index 0000000..d0a2401 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisPubSubController.java @@ -0,0 +1,47 @@ +package com.zhi.demo.controller; + +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.redis.RedisUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Redis 发布订阅 演示案例 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/redis/pubsub") +public class RedisPubSubController { + + /** + * 发布消息 + * + * @param key 通道Key + * @param value 发送内容 + */ + @GetMapping("/pub") + public R pub(String key, String value) { + RedisUtils.publish(key, value, consumer -> { + System.out.println("发布通道 => " + key + ", 发送值 => " + value); + }); + return R.ok("操作成功"); + } + + /** + * 订阅消息 + * + * @param key 通道Key + */ + @GetMapping("/sub") + public R sub(String key) { + RedisUtils.subscribe(key, String.class, msg -> { + System.out.println("订阅通道 => " + key + ", 接收值 => " + msg); + }); + return R.ok("操作成功"); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/RedisRateLimiterController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisRateLimiterController.java new file mode 100644 index 0000000..2af626b --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/RedisRateLimiterController.java @@ -0,0 +1,52 @@ +package com.zhi.demo.controller; + +import com.zhi.common.annotation.RateLimiter; +import com.zhi.common.core.domain.R; +import com.zhi.common.enums.LimitType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + + +/** + * 测试分布式限流样例 + * + * @author Lion Li + */ +@Slf4j +@RestController +@RequestMapping("/demo/rateLimiter") +public class RedisRateLimiterController { + + /** + * 测试全局限流 + * 全局影响 + */ + @RateLimiter(count = 2, time = 10) + @GetMapping("/test") + public R test(String value) { + return R.ok("操作成功", value); + } + + /** + * 测试请求IP限流 + * 同一IP请求受影响 + */ + @RateLimiter(count = 2, time = 10, limitType = LimitType.IP) + @GetMapping("/testip") + public R testip(String value) { + return R.ok("操作成功", value); + } + + /** + * 测试集群实例限流 + * 启动两个后端服务互不影响 + */ + @RateLimiter(count = 2, time = 10, limitType = LimitType.CLUSTER) + @GetMapping("/testcluster") + public R testcluster(String value) { + return R.ok("操作成功", value); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/SmsController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/SmsController.java new file mode 100644 index 0000000..1f6b52e --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/SmsController.java @@ -0,0 +1,76 @@ +package com.zhi.demo.controller; + +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.spring.SpringUtils; +import com.zhi.sms.config.properties.SmsProperties; +import com.zhi.sms.core.SmsTemplate; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.HashMap; +import java.util.Map; + +/** + * 短信演示案例 + * 请先阅读文档 否则无法使用 + * + * @author Lion Li + * @version 4.2.0 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/sms") +public class SmsController { + + private final SmsProperties smsProperties; +// private final SmsTemplate smsTemplate; // 可以使用spring注入 +// private final AliyunSmsTemplate smsTemplate; // 也可以注入某个厂家的模板工具 + + /** + * 发送短信Aliyun + * + * @param phones 电话号 + * @param templateId 模板ID + */ + @GetMapping("/sendAliyun") + public R sendAliyun(String phones, String templateId) { + if (!smsProperties.getEnabled()) { + return R.fail("当前系统没有开启短信功能!"); + } + if (!SpringUtils.containsBean("aliyunSmsTemplate")) { + return R.fail("阿里云依赖未引入!"); + } + SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); + Map map = new HashMap<>(1); + map.put("code", "1234"); + Object send = smsTemplate.send(phones, templateId, map); + return R.ok(send); + } + + /** + * 发送短信Tencent + * + * @param phones 电话号 + * @param templateId 模板ID + */ + @GetMapping("/sendTencent") + public R sendTencent(String phones, String templateId) { + if (!smsProperties.getEnabled()) { + return R.fail("当前系统没有开启短信功能!"); + } + if (!SpringUtils.containsBean("tencentSmsTemplate")) { + return R.fail("腾讯云依赖未引入!"); + } + SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); + Map map = new HashMap<>(1); +// map.put("2", "测试测试"); + map.put("1", "1234"); + Object send = smsTemplate.send(phones, templateId, map); + return R.ok(send); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/Swagger3DemoController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/Swagger3DemoController.java new file mode 100644 index 0000000..f5ad47d --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/Swagger3DemoController.java @@ -0,0 +1,31 @@ +package com.zhi.demo.controller; + +import com.zhi.common.core.domain.R; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +/** + * swagger3 用法示例 + * + * @author Lion Li + */ +@RestController +@RequestMapping("/swagger/demo") +public class Swagger3DemoController { + + /** + * 上传请求 + * 必须使用 @RequestPart 注解标注为文件 + * + * @param file 文件 + */ + @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R upload(@RequestPart("file") MultipartFile file) { + return R.ok("操作成功", file.getOriginalFilename()); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/TestBatchController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/TestBatchController.java new file mode 100644 index 0000000..180ec4f --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/TestBatchController.java @@ -0,0 +1,90 @@ +package com.zhi.demo.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.demo.domain.TestDemo; +import com.zhi.demo.mapper.TestDemoMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.ArrayList; +import java.util.List; + +/** + * 测试批量方法 + * + * @author Lion Li + * @date 2021-05-30 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/batch") +public class TestBatchController extends BaseController { + + /** + * 为了便于测试 直接引入mapper + */ + private final TestDemoMapper testDemoMapper; + + /** + * 新增批量方法 可完美替代 saveBatch 秒级插入上万数据 (对mysql负荷较大) + *

+ * 3.5.0 版本 增加 rewriteBatchedStatements=true 批处理参数 使 MP 原生批处理可以达到同样的速度 + */ + @PostMapping("/add") +// @DS("slave") + public R add() { + List list = new ArrayList<>(); + for (int i = 0; i < 1000; i++) { + TestDemo testDemo = new TestDemo(); + testDemo.setOrderNum(-1); + testDemo.setTestKey("批量新增"); + testDemo.setValue("测试新增"); + list.add(testDemo); + } + return toAjax(testDemoMapper.insertBatch(list)); + } + + /** + * 新增或更新 可完美替代 saveOrUpdateBatch 高性能 + *

+ * 3.5.0 版本 增加 rewriteBatchedStatements=true 批处理参数 使 MP 原生批处理可以达到同样的速度 + */ + @PostMapping("/addOrUpdate") +// @DS("slave") + public R addOrUpdate() { + List list = new ArrayList<>(); + for (int i = 0; i < 1000; i++) { + TestDemo testDemo = new TestDemo(); + testDemo.setOrderNum(-1); + testDemo.setTestKey("批量新增"); + testDemo.setValue("测试新增"); + list.add(testDemo); + } + testDemoMapper.insertBatch(list); + for (int i = 0; i < list.size(); i++) { + TestDemo testDemo = list.get(i); + testDemo.setTestKey("批量新增或修改"); + testDemo.setValue("批量新增或修改"); + if (i % 2 == 0) { + testDemo.setId(null); + } + } + return toAjax(testDemoMapper.insertOrUpdateBatch(list)); + } + + /** + * 删除批量方法 + */ + @DeleteMapping() +// @DS("slave") + public R remove() { + return toAjax(testDemoMapper.delete(new LambdaQueryWrapper() + .eq(TestDemo::getOrderNum, -1L))); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/TestDemoController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/TestDemoController.java new file mode 100644 index 0000000..e11954e --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/TestDemoController.java @@ -0,0 +1,148 @@ +package com.zhi.demo.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.bean.BeanUtil; +import com.zhi.common.annotation.Log; +import com.zhi.common.annotation.RepeatSubmit; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.core.validate.AddGroup; +import com.zhi.common.core.validate.EditGroup; +import com.zhi.common.core.validate.QueryGroup; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.excel.ExcelResult; +import com.zhi.common.utils.ValidatorUtils; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.demo.domain.TestDemo; +import com.zhi.demo.domain.bo.TestDemoBo; +import com.zhi.demo.domain.bo.TestDemoImportVo; +import com.zhi.demo.domain.vo.TestDemoVo; +import com.zhi.demo.service.ITestDemoService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * 测试单表Controller + * + * @author Lion Li + * @date 2021-07-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/demo") +public class TestDemoController extends BaseController { + + private final ITestDemoService iTestDemoService; + + /** + * 查询测试单表列表 + */ + @SaCheckPermission("demo:demo:list") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { + return iTestDemoService.queryPageList(bo, pageQuery); + } + + /** + * 自定义分页查询 + */ + @SaCheckPermission("demo:demo:list") + @GetMapping("/page") + public TableDataInfo page(@Validated(QueryGroup.class) TestDemoBo bo, PageQuery pageQuery) { + return iTestDemoService.customPageList(bo, pageQuery); + } + + /** + * 导入数据 + * + * @param file 导入文件 + */ + @Log(title = "测试单表", businessType = BusinessType.IMPORT) + @SaCheckPermission("demo:demo:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file) throws Exception { + ExcelResult excelResult = ExcelUtil.importExcel(file.getInputStream(), TestDemoImportVo.class, true); + List volist = excelResult.getList(); + List list = BeanUtil.copyToList(volist, TestDemo.class); + iTestDemoService.saveBatch(list); + return R.ok(excelResult.getAnalysis()); + } + + /** + * 导出测试单表列表 + */ + @SaCheckPermission("demo:demo:export") + @Log(title = "测试单表", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(@Validated TestDemoBo bo, HttpServletResponse response) { + List list = iTestDemoService.queryList(bo); + // 测试雪花id导出 +// for (TestDemoVo vo : list) { +// vo.setId(1234567891234567893L); +// } + ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, response); + } + + /** + * 获取测试单表详细信息 + * + * @param id 测试ID + */ + @SaCheckPermission("demo:demo:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("id") Long id) { + return R.ok(iTestDemoService.queryById(id)); + } + + /** + * 新增测试单表 + */ + @SaCheckPermission("demo:demo:add") + @Log(title = "测试单表", businessType = BusinessType.INSERT) + @RepeatSubmit(interval = 2, timeUnit = TimeUnit.SECONDS, message = "{repeat.submit.message}") + @PostMapping() + public R add(@RequestBody TestDemoBo bo) { + // 使用校验工具对标 @Validated(AddGroup.class) 注解 + // 用于在非 Controller 的地方校验对象 + ValidatorUtils.validate(bo, AddGroup.class); + return toAjax(iTestDemoService.insertByBo(bo)); + } + + /** + * 修改测试单表 + */ + @SaCheckPermission("demo:demo:edit") + @Log(title = "测试单表", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestDemoBo bo) { + return toAjax(iTestDemoService.updateByBo(bo)); + } + + /** + * 删除测试单表 + * + * @param ids 测试ID串 + */ + @SaCheckPermission("demo:demo:remove") + @Log(title = "测试单表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iTestDemoService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/TestExcelController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/TestExcelController.java new file mode 100644 index 0000000..8858377 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/TestExcelController.java @@ -0,0 +1,97 @@ +package com.zhi.demo.controller; + +import cn.hutool.core.collection.CollUtil; +import com.zhi.common.utils.poi.ExcelUtil; +import lombok.AllArgsConstructor; +import lombok.Data; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 测试Excel功能 + * + * @author Lion Li + */ +@RestController +@RequestMapping("/demo/excel") +public class TestExcelController { + + /** + * 单列表多数据 + */ + @GetMapping("/exportTemplateOne") + public void exportTemplateOne(HttpServletResponse response) { + Map map = new HashMap<>(); + map.put("title", "单列表多数据"); + map.put("test1", "数据测试1"); + map.put("test2", "数据测试2"); + map.put("test3", "数据测试3"); + map.put("test4", "数据测试4"); + map.put("testTest", "666"); + List list = new ArrayList<>(); + list.add(new TestObj("单列表测试1", "列表测试1", "列表测试2", "列表测试3", "列表测试4")); + list.add(new TestObj("单列表测试2", "列表测试5", "列表测试6", "列表测试7", "列表测试8")); + list.add(new TestObj("单列表测试3", "列表测试9", "列表测试10", "列表测试11", "列表测试12")); + ExcelUtil.exportTemplate(CollUtil.newArrayList(map, list), "单列表.xlsx", "excel/单列表.xlsx", response); + } + + /** + * 多列表多数据 + */ + @GetMapping("/exportTemplateMuliti") + public void exportTemplateMuliti(HttpServletResponse response) { + Map map = new HashMap<>(); + map.put("title1", "标题1"); + map.put("title2", "标题2"); + map.put("title3", "标题3"); + map.put("title4", "标题4"); + map.put("author", "Lion Li"); + List list1 = new ArrayList<>(); + list1.add(new TestObj1("list1测试1", "list1测试2", "list1测试3")); + list1.add(new TestObj1("list1测试4", "list1测试5", "list1测试6")); + list1.add(new TestObj1("list1测试7", "list1测试8", "list1测试9")); + List list2 = new ArrayList<>(); + list2.add(new TestObj1("list2测试1", "list2测试2", "list2测试3")); + list2.add(new TestObj1("list2测试4", "list2测试5", "list2测试6")); + List list3 = new ArrayList<>(); + list3.add(new TestObj1("list3测试1", "list3测试2", "list3测试3")); + List list4 = new ArrayList<>(); + list4.add(new TestObj1("list4测试1", "list4测试2", "list4测试3")); + list4.add(new TestObj1("list4测试4", "list4测试5", "list4测试6")); + list4.add(new TestObj1("list4测试7", "list4测试8", "list4测试9")); + list4.add(new TestObj1("list4测试10", "list4测试11", "list4测试12")); + Map multiListMap = new HashMap<>(); + multiListMap.put("map", map); + multiListMap.put("data1", list1); + multiListMap.put("data2", list2); + multiListMap.put("data3", list3); + multiListMap.put("data4", list4); + ExcelUtil.exportTemplateMultiList(multiListMap, "多列表.xlsx", "excel/多列表.xlsx", response); + } + + @Data + @AllArgsConstructor + static class TestObj1 { + private String test1; + private String test2; + private String test3; + } + + @Data + @AllArgsConstructor + static class TestObj { + private String name; + private String list1; + private String list2; + private String list3; + private String list4; + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/TestI18nController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/TestI18nController.java new file mode 100644 index 0000000..71e709e --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/TestI18nController.java @@ -0,0 +1,71 @@ +package com.zhi.demo.controller; + +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.MessageUtils; +import lombok.Data; +import org.hibernate.validator.constraints.Range; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + + +/** + * 测试国际化 + * + * @author Lion Li + */ +@Validated +@RestController +@RequestMapping("/demo/i18n") +public class TestI18nController { + + /** + * 通过code获取国际化内容 + * code为 messages.properties 中的 key + *

+ * 测试使用 user.register.success + * + * @param code 国际化code + */ + @GetMapping() + public R get(String code) { + return R.ok(MessageUtils.message(code)); + } + + /** + * Validator 校验国际化 + * 不传值 分别查看异常返回 + *

+ * 测试使用 not.null + */ + @GetMapping("/test1") + public R test1(@NotBlank(message = "{not.null}") String str) { + return R.ok(str); + } + + /** + * Bean 校验国际化 + * 不传值 分别查看异常返回 + *

+ * 测试使用 not.null + */ + @GetMapping("/test2") + public R test2(@Validated TestI18nBo bo) { + return R.ok(bo); + } + + @Data + public static class TestI18nBo { + + @NotBlank(message = "{not.null}") + private String name; + + @NotNull(message = "{not.null}") + @Range(min = 0, max = 100, message = "{length.not.valid}") + private Integer age; + } +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/TestSensitiveController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/TestSensitiveController.java new file mode 100644 index 0000000..6645a23 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/TestSensitiveController.java @@ -0,0 +1,75 @@ +package com.zhi.demo.controller; + +import com.zhi.common.annotation.Sensitive; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.enums.SensitiveStrategy; +import lombok.Data; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 测试数据脱敏控制器 + *

+ * 默认管理员不过滤 + * 需自行根据业务重写实现 + * + * @author Lion Li + * @version 3.6.0 + * @see com.zhi.common.core.service.SensitiveService + */ +@RestController +@RequestMapping("/demo/sensitive") +public class TestSensitiveController extends BaseController { + + /** + * 测试数据脱敏 + */ + @GetMapping("/test") + public R test() { + TestSensitive testSensitive = new TestSensitive(); + testSensitive.setIdCard("210397198608215431"); + testSensitive.setPhone("17640125371"); + testSensitive.setAddress("北京市朝阳区某某四合院1203室"); + testSensitive.setEmail("17640125371@163.com"); + testSensitive.setBankCard("6226456952351452853"); + return R.ok(testSensitive); + } + + @Data + static class TestSensitive { + + /** + * 身份证 + */ + @Sensitive(strategy = SensitiveStrategy.ID_CARD) + private String idCard; + + /** + * 电话 + */ + @Sensitive(strategy = SensitiveStrategy.PHONE) + private String phone; + + /** + * 地址 + */ + @Sensitive(strategy = SensitiveStrategy.ADDRESS) + private String address; + + /** + * 邮箱 + */ + @Sensitive(strategy = SensitiveStrategy.EMAIL) + private String email; + + /** + * 银行卡 + */ + @Sensitive(strategy = SensitiveStrategy.BANK_CARD) + private String bankCard; + + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/TestTreeController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/TestTreeController.java new file mode 100644 index 0000000..31992c9 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/TestTreeController.java @@ -0,0 +1,107 @@ +package com.zhi.demo.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import com.zhi.common.annotation.Log; +import com.zhi.common.annotation.RepeatSubmit; +import com.zhi.common.core.controller.BaseController; +import com.zhi.common.core.domain.R; +import com.zhi.common.core.validate.AddGroup; +import com.zhi.common.core.validate.EditGroup; +import com.zhi.common.core.validate.QueryGroup; +import com.zhi.common.enums.BusinessType; +import com.zhi.common.utils.poi.ExcelUtil; +import com.zhi.demo.domain.bo.TestTreeBo; +import com.zhi.demo.domain.vo.TestTreeVo; +import com.zhi.demo.service.ITestTreeService; +import lombok.RequiredArgsConstructor; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 测试树表Controller + * + * @author Lion Li + * @date 2021-07-26 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/tree") +public class TestTreeController extends BaseController { + + private final ITestTreeService iTestTreeService; + + /** + * 查询测试树表列表 + */ + @SaCheckPermission("demo:tree:list") + @GetMapping("/list") + public R> list(@Validated(QueryGroup.class) TestTreeBo bo) { + List list = iTestTreeService.queryList(bo); + return R.ok(list); + } + + /** + * 导出测试树表列表 + */ + @SaCheckPermission("demo:tree:export") + @Log(title = "测试树表", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated TestTreeBo bo, HttpServletResponse response) { + List list = iTestTreeService.queryList(bo); + ExcelUtil.exportExcel(list, "测试树表", TestTreeVo.class, response); + } + + /** + * 获取测试树表详细信息 + * + * @param id 测试树ID + */ + @SaCheckPermission("demo:tree:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable("id") Long id) { + return R.ok(iTestTreeService.queryById(id)); + } + + /** + * 新增测试树表 + */ + @SaCheckPermission("demo:tree:add") + @Log(title = "测试树表", businessType = BusinessType.INSERT) + @RepeatSubmit + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody TestTreeBo bo) { + return toAjax(iTestTreeService.insertByBo(bo)); + } + + /** + * 修改测试树表 + */ + @SaCheckPermission("demo:tree:edit") + @Log(title = "测试树表", businessType = BusinessType.UPDATE) + @RepeatSubmit + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody TestTreeBo bo) { + return toAjax(iTestTreeService.updateByBo(bo)); + } + + /** + * 删除测试树表 + * + * @param ids 测试树ID串 + */ + @SaCheckPermission("demo:tree:remove") + @Log(title = "测试树表", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iTestTreeService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/package-info.java b/zhi-demo/src/main/java/com/zhi/demo/controller/package-info.java new file mode 100644 index 0000000..9c7b057 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/package-info.java @@ -0,0 +1 @@ +package com.zhi.demo.controller; diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/queue/BoundedQueueController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/BoundedQueueController.java new file mode 100644 index 0000000..0094a33 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/BoundedQueueController.java @@ -0,0 +1,90 @@ +package com.zhi.demo.controller.queue; + +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.redis.QueueUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 有界队列 演示案例 + *

+ * 轻量级队列 重量级数据量 请使用 MQ + *

+ * 集群测试通过 同一个数据只会被消费一次 做好事务补偿 + * 集群测试流程 在其中一台发送数据 两端分别调用获取接口 一次获取一条 + * + * @author Lion Li + * @version 3.6.0 + */ +@Slf4j +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/queue/bounded") +public class BoundedQueueController { + + + /** + * 添加队列数据 + * + * @param queueName 队列名 + * @param capacity 容量 + */ + @GetMapping("/add") + public R add(String queueName, int capacity) { + // 用完了一定要销毁 否则会一直存在 + boolean b = QueueUtils.destroyQueue(queueName); + log.info("通道: {} , 删除: {}", queueName, b); + // 初始化设置一次即可 + if (QueueUtils.trySetBoundedQueueCapacity(queueName, capacity)) { + log.info("通道: {} , 设置容量: {}", queueName, capacity); + } else { + log.info("通道: {} , 设置容量失败", queueName); + return R.fail("操作失败"); + } + for (int i = 0; i < 11; i++) { + String data = "data-" + i; + boolean flag = QueueUtils.addBoundedQueueObject(queueName, data); + if (flag == false) { + log.info("通道: {} , 发送数据: {} 失败, 通道已满", queueName, data); + } else { + log.info("通道: {} , 发送数据: {}", queueName, data); + } + } + return R.ok("操作成功"); + } + + /** + * 删除队列数据 + * + * @param queueName 队列名 + */ + @GetMapping("/remove") + public R remove(String queueName) { + String data = "data-" + 5; + if (QueueUtils.removeQueueObject(queueName, data)) { + log.info("通道: {} , 删除数据: {}", queueName, data); + } else { + return R.fail("操作失败"); + } + return R.ok("操作成功"); + } + + /** + * 获取队列数据 + * + * @param queueName 队列名 + */ + @GetMapping("/get") + public R get(String queueName) { + String data; + do { + data = QueueUtils.getQueueObject(queueName); + log.info("通道: {} , 获取数据: {}", queueName, data); + } while (data != null); + return R.ok("操作成功"); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/queue/DelayedQueueController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/DelayedQueueController.java new file mode 100644 index 0000000..b8eb1c2 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/DelayedQueueController.java @@ -0,0 +1,90 @@ +package com.zhi.demo.controller.queue; + +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.redis.QueueUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.concurrent.TimeUnit; + +/** + * 延迟队列 演示案例 + *

+ * 轻量级队列 重量级数据量 请使用 MQ + * 例如: 创建订单30分钟后过期处理 + *

+ * 集群测试通过 同一个数据只会被消费一次 做好事务补偿 + * 集群测试流程 两台集群分别开启订阅 在其中一台发送数据 观察接收消息的规律 + * + * @author Lion Li + * @version 3.6.0 + */ +@Slf4j +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/queue/delayed") +public class DelayedQueueController { + + /** + * 订阅队列 + * + * @param queueName 队列名 + */ + @GetMapping("/subscribe") + public R subscribe(String queueName) { + log.info("通道: {} 监听中......", queueName); + // 项目初始化设置一次即可 + QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> { + // 观察接收时间 + log.info("通道: {}, 收到数据: {}", queueName, orderNum); + }); + return R.ok("操作成功"); + } + + /** + * 添加队列数据 + * + * @param queueName 队列名 + * @param orderNum 订单号 + * @param time 延迟时间(秒) + */ + @GetMapping("/add") + public R add(String queueName, String orderNum, Long time) { + QueueUtils.addDelayedQueueObject(queueName, orderNum, time, TimeUnit.SECONDS); + // 观察发送时间 + log.info("通道: {} , 发送数据: {}", queueName, orderNum); + return R.ok("操作成功"); + } + + /** + * 删除队列数据 + * + * @param queueName 队列名 + * @param orderNum 订单号 + */ + @GetMapping("/remove") + public R remove(String queueName, String orderNum) { + if (QueueUtils.removeDelayedQueueObject(queueName, orderNum)) { + log.info("通道: {} , 删除数据: {}", queueName, orderNum); + } else { + return R.fail("操作失败"); + } + return R.ok("操作成功"); + } + + /** + * 销毁队列 + * + * @param queueName 队列名 + */ + @GetMapping("/destroy") + public R destroy(String queueName) { + // 用完了一定要销毁 否则会一直存在 + QueueUtils.destroyDelayedQueue(queueName); + return R.ok("操作成功"); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/queue/PriorityDemo.java b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/PriorityDemo.java new file mode 100644 index 0000000..6bd5d67 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/PriorityDemo.java @@ -0,0 +1,23 @@ +package com.zhi.demo.controller.queue; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jetbrains.annotations.NotNull; + +/** + * 实体类 注意不允许使用内部类 否则会找不到类 + * + * @author Lion Li + * @version 3.6.0 + */ +@Data +@NoArgsConstructor +public class PriorityDemo implements Comparable { + private String name; + private Integer orderNum; + + @Override + public int compareTo(@NotNull PriorityDemo other) { + return Integer.compare(getOrderNum(), other.getOrderNum()); + } +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/controller/queue/PriorityQueueController.java b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/PriorityQueueController.java new file mode 100644 index 0000000..697cb96 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/controller/queue/PriorityQueueController.java @@ -0,0 +1,89 @@ +package com.zhi.demo.controller.queue; + +import cn.hutool.core.util.RandomUtil; +import com.zhi.common.core.domain.R; +import com.zhi.common.utils.redis.QueueUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 优先队列 演示案例 + *

+ * 轻量级队列 重量级数据量 请使用 MQ + *

+ * 集群测试通过 同一个消息只会被消费一次 做好事务补偿 + * 集群测试流程 在其中一台发送数据 两端分别调用获取接口 一次获取一条 + * + * @author Lion Li + * @version 3.6.0 + */ +@Slf4j +@RequiredArgsConstructor +@RestController +@RequestMapping("/demo/queue/priority") +public class PriorityQueueController { + + /** + * 添加队列数据 + * + * @param queueName 队列名 + */ + @GetMapping("/add") + public R add(String queueName) { + // 用完了一定要销毁 否则会一直存在 + boolean b = QueueUtils.destroyQueue(queueName); + log.info("通道: {} , 删除: {}", queueName, b); + + for (int i = 0; i < 10; i++) { + int randomNum = RandomUtil.randomInt(10); + PriorityDemo data = new PriorityDemo(); + data.setName("data-" + i); + data.setOrderNum(randomNum); + if (QueueUtils.addPriorityQueueObject(queueName, data)) { + log.info("通道: {} , 发送数据: {}", queueName, data); + } else { + log.info("通道: {} , 发送数据: {}, 发送失败", queueName, data); + } + } + return R.ok("操作成功"); + } + + /** + * 删除队列数据 + * + * @param queueName 队列名 + * @param name 对象名 + * @param orderNum 排序号 + */ + @GetMapping("/remove") + public R remove(String queueName, String name, Integer orderNum) { + PriorityDemo data = new PriorityDemo(); + data.setName(name); + data.setOrderNum(orderNum); + if (QueueUtils.removeQueueObject(queueName, data)) { + log.info("通道: {} , 删除数据: {}", queueName, data); + } else { + return R.fail("操作失败"); + } + return R.ok("操作成功"); + } + + /** + * 获取队列数据 + * + * @param queueName 队列名 + */ + @GetMapping("/get") + public R get(String queueName) { + PriorityDemo data; + do { + data = QueueUtils.getQueueObject(queueName); + log.info("通道: {} , 获取数据: {}", queueName, data); + } while (data != null); + return R.ok("操作成功"); + } + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/TestDemo.java b/zhi-demo/src/main/java/com/zhi/demo/domain/TestDemo.java new file mode 100644 index 0000000..917b58a --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/TestDemo.java @@ -0,0 +1,66 @@ +package com.zhi.demo.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.zhi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 测试单表对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_demo") +public class TestDemo extends BaseEntity { + + private static final long serialVersionUID = 1L; + + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 部门id + */ + private Long deptId; + + /** + * 用户id + */ + private Long userId; + + /** + * 排序号 + */ + @OrderBy(asc = false, sort = 1) + private Integer orderNum; + + /** + * key键 + */ + private String testKey; + + /** + * 值 + */ + private String value; + + /** + * 版本 + */ + @Version + private Long version; + + /** + * 删除标志 + */ + @TableLogic + private Long delFlag; + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/TestTree.java b/zhi-demo/src/main/java/com/zhi/demo/domain/TestTree.java new file mode 100644 index 0000000..a1206de --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/TestTree.java @@ -0,0 +1,58 @@ +package com.zhi.demo.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.Version; +import com.zhi.common.core.domain.TreeEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 测试树表对象 test_tree + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("test_tree") +public class TestTree extends TreeEntity { + + private static final long serialVersionUID = 1L; + + + /** + * 主键 + */ + @TableId(value = "id") + private Long id; + + /** + * 部门id + */ + private Long deptId; + + /** + * 用户id + */ + private Long userId; + + /** + * 树节点名 + */ + private String treeName; + + /** + * 版本 + */ + @Version + private Long version; + + /** + * 删除标志 + */ + @TableLogic + private Long delFlag; + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestDemoBo.java b/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestDemoBo.java new file mode 100644 index 0000000..736eb59 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestDemoBo.java @@ -0,0 +1,59 @@ +package com.zhi.demo.domain.bo; + +import com.zhi.common.core.domain.BaseEntity; +import com.zhi.common.core.validate.AddGroup; +import com.zhi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 测试单表业务对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class TestDemoBo extends BaseEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 部门id + */ + @NotNull(message = "部门id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long deptId; + + /** + * 用户id + */ + @NotNull(message = "用户id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long userId; + + /** + * 排序号 + */ + @NotNull(message = "排序号不能为空", groups = {AddGroup.class, EditGroup.class}) + private Integer orderNum; + + /** + * key键 + */ + @NotBlank(message = "key键不能为空", groups = {AddGroup.class, EditGroup.class}) + private String testKey; + + /** + * 值 + */ + @NotBlank(message = "值不能为空", groups = {AddGroup.class, EditGroup.class}) + private String value; + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestDemoImportVo.java b/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestDemoImportVo.java new file mode 100644 index 0000000..6203a00 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestDemoImportVo.java @@ -0,0 +1,53 @@ +package com.zhi.demo.domain.bo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 测试单表业务对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +public class TestDemoImportVo { + + /** + * 部门id + */ + @NotNull(message = "部门id不能为空") + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 用户id + */ + @NotNull(message = "用户id不能为空") + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 排序号 + */ + @NotNull(message = "排序号不能为空") + @ExcelProperty(value = "排序号") + private Long orderNum; + + /** + * key键 + */ + @NotBlank(message = "key键不能为空") + @ExcelProperty(value = "key键") + private String testKey; + + /** + * 值 + */ + @NotBlank(message = "值不能为空") + @ExcelProperty(value = "值") + private String value; + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestTreeBo.java b/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestTreeBo.java new file mode 100644 index 0000000..1d8a26c --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/bo/TestTreeBo.java @@ -0,0 +1,47 @@ +package com.zhi.demo.domain.bo; + +import com.zhi.common.core.domain.TreeEntity; +import com.zhi.common.core.validate.AddGroup; +import com.zhi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 测试树表业务对象 test_tree + * + * @author Lion Li + * @date 2021-07-26 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class TestTreeBo extends TreeEntity { + + /** + * 主键 + */ + @NotNull(message = "主键不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 部门id + */ + @NotNull(message = "部门id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long deptId; + + /** + * 用户id + */ + @NotNull(message = "用户id不能为空", groups = {AddGroup.class, EditGroup.class}) + private Long userId; + + /** + * 树节点名 + */ + @NotBlank(message = "树节点名不能为空", groups = {AddGroup.class, EditGroup.class}) + private String treeName; + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/package-info.java b/zhi-demo/src/main/java/com/zhi/demo/domain/package-info.java new file mode 100644 index 0000000..7846a53 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/package-info.java @@ -0,0 +1 @@ +package com.zhi.demo.domain; diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/vo/TestDemoVo.java b/zhi-demo/src/main/java/com/zhi/demo/domain/vo/TestDemoVo.java new file mode 100644 index 0000000..4118934 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/vo/TestDemoVo.java @@ -0,0 +1,83 @@ +package com.zhi.demo.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.Date; + + +/** + * 测试单表视图对象 test_demo + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@ExcelIgnoreUnannotated +public class TestDemoVo { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + @ExcelProperty(value = "主键") + private Long id; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 排序号 + */ + @ExcelProperty(value = "排序号") + private Integer orderNum; + + /** + * key键 + */ + @ExcelProperty(value = "key键") + private String testKey; + + /** + * 值 + */ + @ExcelProperty(value = "值") + private String value; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + /** + * 创建人 + */ + @ExcelProperty(value = "创建人") + private String createBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + private Date updateTime; + + /** + * 更新人 + */ + @ExcelProperty(value = "更新人") + private String updateBy; + + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/domain/vo/TestTreeVo.java b/zhi-demo/src/main/java/com/zhi/demo/domain/vo/TestTreeVo.java new file mode 100644 index 0000000..4b6ea49 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/domain/vo/TestTreeVo.java @@ -0,0 +1,58 @@ +package com.zhi.demo.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +import java.util.Date; + + +/** + * 测试树表视图对象 test_tree + * + * @author Lion Li + * @date 2021-07-26 + */ +@Data +@ExcelIgnoreUnannotated +public class TestTreeVo { + + private static final long serialVersionUID = 1L; + + /** + * 主键 + */ + private Long id; + + /** + * 父id + */ + @ExcelProperty(value = "父id") + private Long parentId; + + /** + * 部门id + */ + @ExcelProperty(value = "部门id") + private Long deptId; + + /** + * 用户id + */ + @ExcelProperty(value = "用户id") + private Long userId; + + /** + * 树节点名 + */ + @ExcelProperty(value = "树节点名") + private String treeName; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + private Date createTime; + + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/mapper/TestDemoMapper.java b/zhi-demo/src/main/java/com/zhi/demo/mapper/TestDemoMapper.java new file mode 100644 index 0000000..8929526 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/mapper/TestDemoMapper.java @@ -0,0 +1,58 @@ +package com.zhi.demo.mapper; + +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Constants; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zhi.common.annotation.DataColumn; +import com.zhi.common.annotation.DataPermission; +import com.zhi.common.core.mapper.BaseMapperPlus; +import com.zhi.demo.domain.TestDemo; +import com.zhi.demo.domain.vo.TestDemoVo; +import org.apache.ibatis.annotations.Param; + +import java.util.Collection; +import java.util.List; + +/** + * 测试单表Mapper接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +public interface TestDemoMapper extends BaseMapperPlus { + + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + Page customPageList(@Param("page") Page page, @Param("ew") Wrapper wrapper); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) +

> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int updateById(@Param(Constants.ENTITY) TestDemo entity); + + @Override + @DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") + }) + int deleteBatchIds(@Param(Constants.COLL) Collection idList); +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/mapper/TestTreeMapper.java b/zhi-demo/src/main/java/com/zhi/demo/mapper/TestTreeMapper.java new file mode 100644 index 0000000..a10196a --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/mapper/TestTreeMapper.java @@ -0,0 +1,21 @@ +package com.zhi.demo.mapper; + +import com.zhi.common.annotation.DataColumn; +import com.zhi.common.annotation.DataPermission; +import com.zhi.common.core.mapper.BaseMapperPlus; +import com.zhi.demo.domain.TestTree; +import com.zhi.demo.domain.vo.TestTreeVo; + +/** + * 测试树表Mapper接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +@DataPermission({ + @DataColumn(key = "deptName", value = "dept_id"), + @DataColumn(key = "userName", value = "user_id") +}) +public interface TestTreeMapper extends BaseMapperPlus { + +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/mapper/package-info.java b/zhi-demo/src/main/java/com/zhi/demo/mapper/package-info.java new file mode 100644 index 0000000..492ddee --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/mapper/package-info.java @@ -0,0 +1 @@ +package com.zhi.demo.mapper; diff --git a/zhi-demo/src/main/java/com/zhi/demo/service/ITestDemoService.java b/zhi-demo/src/main/java/com/zhi/demo/service/ITestDemoService.java new file mode 100644 index 0000000..a39762f --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/service/ITestDemoService.java @@ -0,0 +1,71 @@ +package com.zhi.demo.service; + +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.demo.domain.TestDemo; +import com.zhi.demo.domain.bo.TestDemoBo; +import com.zhi.demo.domain.vo.TestDemoVo; + +import java.util.Collection; +import java.util.List; + +/** + * 测试单表Service接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +public interface ITestDemoService { + + /** + * 查询单个 + * + * @return + */ + TestDemoVo queryById(Long id); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(TestDemoBo bo, PageQuery pageQuery); + + /** + * 自定义分页查询 + */ + TableDataInfo customPageList(TestDemoBo bo, PageQuery pageQuery); + + /** + * 查询列表 + */ + List queryList(TestDemoBo bo); + + /** + * 根据新增业务对象插入测试单表 + * + * @param bo 测试单表新增业务对象 + * @return + */ + Boolean insertByBo(TestDemoBo bo); + + /** + * 根据编辑业务对象修改测试单表 + * + * @param bo 测试单表编辑业务对象 + * @return + */ + Boolean updateByBo(TestDemoBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 批量保存 + */ + Boolean saveBatch(List list); +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/service/ITestTreeService.java b/zhi-demo/src/main/java/com/zhi/demo/service/ITestTreeService.java new file mode 100644 index 0000000..6b99490 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/service/ITestTreeService.java @@ -0,0 +1,52 @@ +package com.zhi.demo.service; + +import com.zhi.demo.domain.bo.TestTreeBo; +import com.zhi.demo.domain.vo.TestTreeVo; + +import java.util.Collection; +import java.util.List; + +/** + * 测试树表Service接口 + * + * @author Lion Li + * @date 2021-07-26 + */ +public interface ITestTreeService { + /** + * 查询单个 + * + * @return + */ + TestTreeVo queryById(Long id); + + /** + * 查询列表 + */ + List queryList(TestTreeBo bo); + + /** + * 根据新增业务对象插入测试树表 + * + * @param bo 测试树表新增业务对象 + * @return + */ + Boolean insertByBo(TestTreeBo bo); + + /** + * 根据编辑业务对象修改测试树表 + * + * @param bo 测试树表编辑业务对象 + * @return + */ + Boolean updateByBo(TestTreeBo bo); + + /** + * 校验并删除数据 + * + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/service/impl/TestDemoServiceImpl.java b/zhi-demo/src/main/java/com/zhi/demo/service/impl/TestDemoServiceImpl.java new file mode 100644 index 0000000..03a4094 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/service/impl/TestDemoServiceImpl.java @@ -0,0 +1,110 @@ +package com.zhi.demo.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.zhi.common.core.domain.PageQuery; +import com.zhi.common.core.page.TableDataInfo; +import com.zhi.common.utils.StringUtils; +import com.zhi.demo.domain.TestDemo; +import com.zhi.demo.domain.bo.TestDemoBo; +import com.zhi.demo.domain.vo.TestDemoVo; +import com.zhi.demo.mapper.TestDemoMapper; +import com.zhi.demo.service.ITestDemoService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 测试单表Service业务层处理 + * + * @author Lion Li + * @date 2021-07-26 + */ +@RequiredArgsConstructor +@Service +public class TestDemoServiceImpl implements ITestDemoService { + + private final TestDemoMapper baseMapper; + + @Override + public TestDemoVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + @Override + public TableDataInfo queryPageList(TestDemoBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 自定义分页查询 + */ + @Override + public TableDataInfo customPageList(TestDemoBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.customPageList(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + @Override + public List queryList(TestDemoBo bo) { + return baseMapper.selectVoList(buildQueryWrapper(bo)); + } + + private LambdaQueryWrapper buildQueryWrapper(TestDemoBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getTestKey()), TestDemo::getTestKey, bo.getTestKey()); + lqw.eq(StringUtils.isNotBlank(bo.getValue()), TestDemo::getValue, bo.getValue()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + TestDemo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + return lqw; + } + + @Override + public Boolean insertByBo(TestDemoBo bo) { + TestDemo add = BeanUtil.toBean(bo, TestDemo.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + @Override + public Boolean updateByBo(TestDemoBo bo) { + TestDemo update = BeanUtil.toBean(bo, TestDemo.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(TestDemo entity) { + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + public Boolean saveBatch(List list) { + return baseMapper.insertBatch(list); + } +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/service/impl/TestTreeServiceImpl.java b/zhi-demo/src/main/java/com/zhi/demo/service/impl/TestTreeServiceImpl.java new file mode 100644 index 0000000..4ca7799 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/service/impl/TestTreeServiceImpl.java @@ -0,0 +1,87 @@ +package com.zhi.demo.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.zhi.common.utils.StringUtils; +import com.zhi.demo.domain.TestTree; +import com.zhi.demo.domain.bo.TestTreeBo; +import com.zhi.demo.domain.vo.TestTreeVo; +import com.zhi.demo.mapper.TestTreeMapper; +import com.zhi.demo.service.ITestTreeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 测试树表Service业务层处理 + * + * @author Lion Li + * @date 2021-07-26 + */ +// @DS("slave") // 切换从库查询 +@RequiredArgsConstructor +@Service +public class TestTreeServiceImpl implements ITestTreeService { + + private final TestTreeMapper baseMapper; + + @Override + public TestTreeVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + // @DS("slave") // 切换从库查询 + @Override + public List queryList(TestTreeBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(TestTreeBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getTreeName()), TestTree::getTreeName, bo.getTreeName()); + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + TestTree::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + return lqw; + } + + @Override + public Boolean insertByBo(TestTreeBo bo) { + TestTree add = BeanUtil.toBean(bo, TestTree.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + @Override + public Boolean updateByBo(TestTreeBo bo) { + TestTree update = BeanUtil.toBean(bo, TestTree.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(TestTree entity) { + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/zhi-demo/src/main/java/com/zhi/demo/service/impl/package-info.java b/zhi-demo/src/main/java/com/zhi/demo/service/impl/package-info.java new file mode 100644 index 0000000..175f973 --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/service/impl/package-info.java @@ -0,0 +1 @@ +package com.zhi.demo.service.impl; diff --git a/zhi-demo/src/main/java/com/zhi/demo/service/package-info.java b/zhi-demo/src/main/java/com/zhi/demo/service/package-info.java new file mode 100644 index 0000000..b89384b --- /dev/null +++ b/zhi-demo/src/main/java/com/zhi/demo/service/package-info.java @@ -0,0 +1 @@ +package com.zhi.demo.service; diff --git a/zhi-demo/src/main/resources/excel/单列表.xlsx b/zhi-demo/src/main/resources/excel/单列表.xlsx new file mode 100644 index 0000000..0f7347d Binary files /dev/null and b/zhi-demo/src/main/resources/excel/单列表.xlsx differ diff --git a/zhi-demo/src/main/resources/excel/多列表.xlsx b/zhi-demo/src/main/resources/excel/多列表.xlsx new file mode 100644 index 0000000..c7d11dc Binary files /dev/null and b/zhi-demo/src/main/resources/excel/多列表.xlsx differ diff --git a/zhi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml b/zhi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml new file mode 100644 index 0000000..a784fdb --- /dev/null +++ b/zhi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/zhi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml b/zhi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml new file mode 100644 index 0000000..182dca1 --- /dev/null +++ b/zhi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/zhi-demo/src/main/resources/mapper/package-info.md b/zhi-demo/src/main/resources/mapper/package-info.md new file mode 100644 index 0000000..c938b1e --- /dev/null +++ b/zhi-demo/src/main/resources/mapper/package-info.md @@ -0,0 +1,3 @@ +java包使用 `.` 分割 resource 目录使用 `/` 分割 +
+此文件目的 防止文件夹粘连找不到 `xml` 文件 \ No newline at end of file diff --git a/zhi-extend/pom.xml b/zhi-extend/pom.xml new file mode 100644 index 0000000..4385ad5 --- /dev/null +++ b/zhi-extend/pom.xml @@ -0,0 +1,18 @@ + + + + ruoyi-vue-plus + com.zhi + 4.4.0 + + 4.0.0 + zhi-extend + pom + + + zhi-xxl-job-admin + + + diff --git a/zhi-extend/zhi-xxl-job-admin/Dockerfile b/zhi-extend/zhi-xxl-job-admin/Dockerfile new file mode 100644 index 0000000..2610889 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/Dockerfile @@ -0,0 +1,16 @@ +FROM anapsix/alpine-java:8_server-jre_unlimited + +MAINTAINER Lion Li + +RUN mkdir -p /ruoyi/xxljob/logs + +WORKDIR /ruoyi/xxljob + +ENV TZ=PRC +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +EXPOSE 9100 + +ADD ./target/zhi-xxl-job-admin.jar ./app.jar + +ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"] diff --git a/zhi-extend/zhi-xxl-job-admin/pom.xml b/zhi-extend/zhi-xxl-job-admin/pom.xml new file mode 100644 index 0000000..3f32c0d --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/pom.xml @@ -0,0 +1,95 @@ + + 4.0.0 + + zhi-extend + com.zhi + 4.4.0 + + zhi-xxl-job-admin + jar + + + + + + + + org.springframework.boot + spring-boot-starter-parent + ${spring-boot.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + + org.springframework.boot + spring-boot-starter-mail + + + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${spring-boot.mybatis} + + + + com.mysql + mysql-connector-j + + + + + + + com.xuxueli + xxl-job-core + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java new file mode 100644 index 0000000..95ec1c4 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java @@ -0,0 +1,16 @@ +package com.xxl.job.admin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author xuxueli 2018-10-28 00:38:13 + */ +@SpringBootApplication +public class XxlJobAdminApplication { + + public static void main(String[] args) { + SpringApplication.run(XxlJobAdminApplication.class, args); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java new file mode 100644 index 0000000..bbb2507 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java @@ -0,0 +1,97 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.controller.annotation.PermissionLimit; +import com.xxl.job.admin.service.LoginService; +import com.xxl.job.admin.service.XxlJobService; +import com.xxl.job.core.biz.model.ReturnT; +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.InitBinder; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.view.RedirectView; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +public class IndexController { + + @Resource + private XxlJobService xxlJobService; + @Resource + private LoginService loginService; + + + @RequestMapping("/") + public String index(Model model) { + + Map dashboardMap = xxlJobService.dashboardInfo(); + model.addAllAttributes(dashboardMap); + + return "index"; + } + + @RequestMapping("/chartInfo") + @ResponseBody + public ReturnT> chartInfo(Date startDate, Date endDate) { + ReturnT> chartInfo = xxlJobService.chartInfo(startDate, endDate); + return chartInfo; + } + + @RequestMapping("/toLogin") + @PermissionLimit(limit = false) + public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) { + if (loginService.ifLogin(request, response) != null) { + modelAndView.setView(new RedirectView("/", true, false)); + return modelAndView; + } + return new ModelAndView("login"); + } + + @RequestMapping(value = "login", method = RequestMethod.POST) + @ResponseBody + @PermissionLimit(limit = false) + public ReturnT loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember) { + boolean ifRem = (ifRemember != null && ifRemember.trim().length() > 0 && "on".equals(ifRemember)) ? true : false; + return loginService.login(request, response, userName, password, ifRem); + } + + @RequestMapping(value = "logout", method = RequestMethod.POST) + @ResponseBody + @PermissionLimit(limit = false) + public ReturnT logout(HttpServletRequest request, HttpServletResponse response) { + return loginService.logout(request, response); + } + + @RequestMapping("/help") + public String help() { + + /*if (!PermissionInterceptor.ifLogin(request)) { + return "redirect:/toLogin"; + }*/ + + return "help"; + } + + @InitBinder + public void initBinder(WebDataBinder binder) { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setLenient(false); + binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java new file mode 100644 index 0000000..f4a37a7 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java @@ -0,0 +1,72 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.controller.annotation.PermissionLimit; +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.core.biz.AdminBiz; +import com.xxl.job.core.biz.model.HandleCallbackParam; +import com.xxl.job.core.biz.model.RegistryParam; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.util.GsonTool; +import com.xxl.job.core.util.XxlJobRemotingUtil; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +/** + * Created by xuxueli on 17/5/10. + */ +@Controller +@RequestMapping("/api") +public class JobApiController { + + @Resource + private AdminBiz adminBiz; + + /** + * api + * + * @param uri + * @param data + * @return + */ + @RequestMapping("/{uri}") + @ResponseBody + @PermissionLimit(limit = false) + public ReturnT api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) { + + // valid + if (!"POST".equalsIgnoreCase(request.getMethod())) { + return new ReturnT(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support."); + } + if (uri == null || uri.trim().length() == 0) { + return new ReturnT(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty."); + } + if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null + && XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0 + && !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) { + return new ReturnT(ReturnT.FAIL_CODE, "The access token is wrong."); + } + + // services mapping + if ("callback".equals(uri)) { + List callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class); + return adminBiz.callback(callbackParamList); + } else if ("registry".equals(uri)) { + RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class); + return adminBiz.registry(registryParam); + } else if ("registryRemove".equals(uri)) { + RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class); + return adminBiz.registryRemove(registryParam); + } else { + return new ReturnT(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found."); + } + + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java new file mode 100644 index 0000000..9185f86 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java @@ -0,0 +1,97 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLogGlue; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.dao.XxlJobInfoDao; +import com.xxl.job.admin.dao.XxlJobLogGlueDao; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.glue.GlueTypeEnum; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.List; + +/** + * job code controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobcode") +public class JobCodeController { + + @Resource + private XxlJobInfoDao xxlJobInfoDao; + @Resource + private XxlJobLogGlueDao xxlJobLogGlueDao; + + @RequestMapping + public String index(HttpServletRequest request, Model model, int jobId) { + XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId); + List jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId); + + if (jobInfo == null) { + throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid")); + } + if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) { + throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid")); + } + + // valid permission + JobInfoController.validPermission(request, jobInfo.getJobGroup()); + + // Glue类型-字典 + model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); + + model.addAttribute("jobInfo", jobInfo); + model.addAttribute("jobLogGlues", jobLogGlues); + return "jobcode/jobcode.index"; + } + + @RequestMapping("/save") + @ResponseBody + public ReturnT save(Model model, int id, String glueSource, String glueRemark) { + // valid + if (glueRemark == null) { + return new ReturnT(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark"))); + } + if (glueRemark.length() < 4 || glueRemark.length() > 100) { + return new ReturnT(500, I18nUtil.getString("jobinfo_glue_remark_limit")); + } + XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id); + if (exists_jobInfo == null) { + return new ReturnT(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid")); + } + + // update new code + exists_jobInfo.setGlueSource(glueSource); + exists_jobInfo.setGlueRemark(glueRemark); + exists_jobInfo.setGlueUpdatetime(new Date()); + + exists_jobInfo.setUpdateTime(new Date()); + xxlJobInfoDao.update(exists_jobInfo); + + // log old code + XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue(); + xxlJobLogGlue.setJobId(exists_jobInfo.getId()); + xxlJobLogGlue.setGlueType(exists_jobInfo.getGlueType()); + xxlJobLogGlue.setGlueSource(glueSource); + xxlJobLogGlue.setGlueRemark(glueRemark); + + xxlJobLogGlue.setAddTime(new Date()); + xxlJobLogGlue.setUpdateTime(new Date()); + xxlJobLogGlueDao.save(xxlJobLogGlue); + + // remove code backup more than 30 + xxlJobLogGlueDao.removeOld(exists_jobInfo.getId(), 30); + + return ReturnT.SUCCESS; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java new file mode 100644 index 0000000..82ec2de --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java @@ -0,0 +1,198 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobRegistry; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.dao.XxlJobGroupDao; +import com.xxl.job.admin.dao.XxlJobInfoDao; +import com.xxl.job.admin.dao.XxlJobRegistryDao; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.enums.RegistryConfig; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * job group controller + * + * @author xuxueli 2016-10-02 20:52:56 + */ +@Controller +@RequestMapping("/jobgroup") +public class JobGroupController { + + @Resource + public XxlJobInfoDao xxlJobInfoDao; + @Resource + public XxlJobGroupDao xxlJobGroupDao; + @Resource + private XxlJobRegistryDao xxlJobRegistryDao; + + @RequestMapping + public String index(Model model) { + return "jobgroup/jobgroup.index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(HttpServletRequest request, + @RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String appname, String title) { + + // page query + List list = xxlJobGroupDao.pageList(start, length, appname, title); + int list_count = xxlJobGroupDao.pageListCount(start, length, appname, title); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/save") + @ResponseBody + public ReturnT save(XxlJobGroup xxlJobGroup) { + + // valid + if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) { + return new ReturnT(500, (I18nUtil.getString("system_please_input") + "AppName")); + } + if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_appname_length")); + } + if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) { + return new ReturnT(500, "AppName" + I18nUtil.getString("system_unvalid")); + } + if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) { + return new ReturnT(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title"))); + } + if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_title") + I18nUtil.getString("system_unvalid")); + } + if (xxlJobGroup.getAddressType() != 0) { + if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_addressType_limit")); + } + if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList") + I18nUtil.getString("system_unvalid")); + } + + String[] addresss = xxlJobGroup.getAddressList().split(","); + for (String item : addresss) { + if (item == null || item.trim().length() == 0) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList_unvalid")); + } + } + } + + // process + xxlJobGroup.setUpdateTime(new Date()); + + int ret = xxlJobGroupDao.save(xxlJobGroup); + return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL; + } + + @RequestMapping("/update") + @ResponseBody + public ReturnT update(XxlJobGroup xxlJobGroup) { + // valid + if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) { + return new ReturnT(500, (I18nUtil.getString("system_please_input") + "AppName")); + } + if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_appname_length")); + } + if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) { + return new ReturnT(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title"))); + } + if (xxlJobGroup.getAddressType() == 0) { + // 0=自动注册 + List registryList = findRegistryByAppName(xxlJobGroup.getAppname()); + String addressListStr = null; + if (registryList != null && !registryList.isEmpty()) { + Collections.sort(registryList); + addressListStr = ""; + for (String item : registryList) { + addressListStr += item + ","; + } + addressListStr = addressListStr.substring(0, addressListStr.length() - 1); + } + xxlJobGroup.setAddressList(addressListStr); + } else { + // 1=手动录入 + if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_addressType_limit")); + } + String[] addresss = xxlJobGroup.getAddressList().split(","); + for (String item : addresss) { + if (item == null || item.trim().length() == 0) { + return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList_unvalid")); + } + } + } + + // process + xxlJobGroup.setUpdateTime(new Date()); + + int ret = xxlJobGroupDao.update(xxlJobGroup); + return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL; + } + + private List findRegistryByAppName(String appnameParam) { + HashMap> appAddressMap = new HashMap>(); + List list = xxlJobRegistryDao.findAll(RegistryConfig.DEAD_TIMEOUT, new Date()); + if (list != null) { + for (XxlJobRegistry item : list) { + if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) { + String appname = item.getRegistryKey(); + List registryList = appAddressMap.get(appname); + if (registryList == null) { + registryList = new ArrayList(); + } + + if (!registryList.contains(item.getRegistryValue())) { + registryList.add(item.getRegistryValue()); + } + appAddressMap.put(appname, registryList); + } + } + } + return appAddressMap.get(appnameParam); + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(int id) { + + // valid + int count = xxlJobInfoDao.pageListCount(0, 10, id, -1, null, null, null); + if (count > 0) { + return new ReturnT(500, I18nUtil.getString("jobgroup_del_limit_0")); + } + + List allList = xxlJobGroupDao.findAll(); + if (allList.size() == 1) { + return new ReturnT(500, I18nUtil.getString("jobgroup_del_limit_1")); + } + + int ret = xxlJobGroupDao.remove(id); + return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL; + } + + @RequestMapping("/loadById") + @ResponseBody + public ReturnT loadById(int id) { + XxlJobGroup jobGroup = xxlJobGroupDao.load(id); + return jobGroup != null ? new ReturnT(jobGroup) : new ReturnT(ReturnT.FAIL_CODE, null); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java new file mode 100644 index 0000000..157c60b --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java @@ -0,0 +1,180 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.core.exception.XxlJobException; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobUser; +import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; +import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum; +import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum; +import com.xxl.job.admin.core.thread.JobScheduleHelper; +import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; +import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.dao.XxlJobGroupDao; +import com.xxl.job.admin.service.LoginService; +import com.xxl.job.admin.service.XxlJobService; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.util.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + private static Logger logger = LoggerFactory.getLogger(JobInfoController.class); + + @Resource + private XxlJobGroupDao xxlJobGroupDao; + @Resource + private XxlJobService xxlJobService; + + @RequestMapping + public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) { + + // 枚举-字典 + model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表 + model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典 + model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典 + model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values()); // 调度类型 + model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values()); // 调度过期策略 + + // 执行器列表 + List jobGroupList_all = xxlJobGroupDao.findAll(); + + // filter group + List jobGroupList = filterJobGroupByRole(request, jobGroupList_all); + if (jobGroupList == null || jobGroupList.size() == 0) { + throw new XxlJobException(I18nUtil.getString("jobgroup_empty")); + } + + model.addAttribute("JobGroupList", jobGroupList); + model.addAttribute("jobGroup", jobGroup); + + return "jobinfo/jobinfo.index"; + } + + public static List filterJobGroupByRole(HttpServletRequest request, List jobGroupList_all) { + List jobGroupList = new ArrayList<>(); + if (jobGroupList_all != null && jobGroupList_all.size() > 0) { + XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY); + if (loginUser.getRole() == 1) { + jobGroupList = jobGroupList_all; + } else { + List groupIdStrs = new ArrayList<>(); + if (loginUser.getPermission() != null && loginUser.getPermission().trim().length() > 0) { + groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(",")); + } + for (XxlJobGroup groupItem : jobGroupList_all) { + if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) { + jobGroupList.add(groupItem); + } + } + } + } + return jobGroupList; + } + + public static void validPermission(HttpServletRequest request, int jobGroup) { + XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY); + if (!loginUser.validPermission(jobGroup)) { + throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username=" + loginUser.getUsername() + "]"); + } + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) { + + return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author); + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(XxlJobInfo jobInfo) { + return xxlJobService.add(jobInfo); + } + + @RequestMapping("/update") + @ResponseBody + public ReturnT update(XxlJobInfo jobInfo) { + return xxlJobService.update(jobInfo); + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(int id) { + return xxlJobService.remove(id); + } + + @RequestMapping("/stop") + @ResponseBody + public ReturnT pause(int id) { + return xxlJobService.stop(id); + } + + @RequestMapping("/start") + @ResponseBody + public ReturnT start(int id) { + return xxlJobService.start(id); + } + + @RequestMapping("/trigger") + @ResponseBody + //@PermissionLimit(limit = false) + public ReturnT triggerJob(int id, String executorParam, String addressList) { + // force cover job param + if (executorParam == null) { + executorParam = ""; + } + + JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList); + return ReturnT.SUCCESS; + } + + @RequestMapping("/nextTriggerTime") + @ResponseBody + public ReturnT> nextTriggerTime(String scheduleType, String scheduleConf) { + + XxlJobInfo paramXxlJobInfo = new XxlJobInfo(); + paramXxlJobInfo.setScheduleType(scheduleType); + paramXxlJobInfo.setScheduleConf(scheduleConf); + + List result = new ArrayList<>(); + try { + Date lastTime = new Date(); + for (int i = 0; i < 5; i++) { + lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime); + if (lastTime != null) { + result.add(DateUtil.formatDateTime(lastTime)); + } else { + break; + } + } + } catch (Exception e) { + logger.error(e.getMessage(), e); + return new ReturnT>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")) + e.getMessage()); + } + return new ReturnT>(result); + + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java new file mode 100644 index 0000000..3369edb --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java @@ -0,0 +1,234 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.core.exception.XxlJobException; +import com.xxl.job.admin.core.complete.XxlJobCompleter; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; +import com.xxl.job.admin.core.scheduler.XxlJobScheduler; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.dao.XxlJobGroupDao; +import com.xxl.job.admin.dao.XxlJobInfoDao; +import com.xxl.job.admin.dao.XxlJobLogDao; +import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.model.KillParam; +import com.xxl.job.core.biz.model.LogParam; +import com.xxl.job.core.biz.model.LogResult; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.util.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * index controller + * + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/joblog") +public class JobLogController { + private static Logger logger = LoggerFactory.getLogger(JobLogController.class); + + @Resource + private XxlJobGroupDao xxlJobGroupDao; + @Resource + public XxlJobInfoDao xxlJobInfoDao; + @Resource + public XxlJobLogDao xxlJobLogDao; + + @RequestMapping + public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") Integer jobId) { + + // 执行器列表 + List jobGroupList_all = xxlJobGroupDao.findAll(); + + // filter group + List jobGroupList = JobInfoController.filterJobGroupByRole(request, jobGroupList_all); + if (jobGroupList == null || jobGroupList.size() == 0) { + throw new XxlJobException(I18nUtil.getString("jobgroup_empty")); + } + + model.addAttribute("JobGroupList", jobGroupList); + + // 任务 + if (jobId > 0) { + XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId); + if (jobInfo == null) { + throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid")); + } + + model.addAttribute("jobInfo", jobInfo); + + // valid permission + JobInfoController.validPermission(request, jobInfo.getJobGroup()); + } + + return "joblog/joblog.index"; + } + + @RequestMapping("/getJobsByGroup") + @ResponseBody + public ReturnT> getJobsByGroup(int jobGroup) { + List list = xxlJobInfoDao.getJobsByGroup(jobGroup); + return new ReturnT>(list); + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(HttpServletRequest request, + @RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + int jobGroup, int jobId, int logStatus, String filterTime) { + + // valid permission + JobInfoController.validPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (filterTime != null && filterTime.trim().length() > 0) { + String[] temp = filterTime.split(" - "); + if (temp.length == 2) { + triggerTimeStart = DateUtil.parseDateTime(temp[0]); + triggerTimeEnd = DateUtil.parseDateTime(temp[1]); + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/logDetailPage") + public String logDetailPage(int id, Model model) { + + // base check + ReturnT logStatue = ReturnT.SUCCESS; + XxlJobLog jobLog = xxlJobLogDao.load(id); + if (jobLog == null) { + throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid")); + } + + model.addAttribute("triggerCode", jobLog.getTriggerCode()); + model.addAttribute("handleCode", jobLog.getHandleCode()); + model.addAttribute("executorAddress", jobLog.getExecutorAddress()); + model.addAttribute("triggerTime", jobLog.getTriggerTime().getTime()); + model.addAttribute("logId", jobLog.getId()); + return "joblog/joblog.detail"; + } + + @RequestMapping("/logDetailCat") + @ResponseBody + public ReturnT logDetailCat(String executorAddress, long triggerTime, long logId, int fromLineNum) { + try { + ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(executorAddress); + ReturnT logResult = executorBiz.log(new LogParam(triggerTime, logId, fromLineNum)); + + // is end + if (logResult.getContent() != null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) { + XxlJobLog jobLog = xxlJobLogDao.load(logId); + if (jobLog.getHandleCode() > 0) { + logResult.getContent().setEnd(true); + } + } + + return logResult; + } catch (Exception e) { + logger.error(e.getMessage(), e); + return new ReturnT(ReturnT.FAIL_CODE, e.getMessage()); + } + } + + @RequestMapping("/logKill") + @ResponseBody + public ReturnT logKill(int id) { + // base check + XxlJobLog log = xxlJobLogDao.load(id); + XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId()); + if (jobInfo == null) { + return new ReturnT(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid")); + } + if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) { + return new ReturnT(500, I18nUtil.getString("joblog_kill_log_limit")); + } + + // request of kill + ReturnT runResult = null; + try { + ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress()); + runResult = executorBiz.kill(new KillParam(jobInfo.getId())); + } catch (Exception e) { + logger.error(e.getMessage(), e); + runResult = new ReturnT(500, e.getMessage()); + } + + if (ReturnT.SUCCESS_CODE == runResult.getCode()) { + log.setHandleCode(ReturnT.FAIL_CODE); + log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":" + (runResult.getMsg() != null ? runResult.getMsg() : "")); + log.setHandleTime(new Date()); + XxlJobCompleter.updateHandleInfoAndFinish(log); + return new ReturnT(runResult.getMsg()); + } else { + return new ReturnT(500, runResult.getMsg()); + } + } + + @RequestMapping("/clearLog") + @ResponseBody + public ReturnT clearLog(int jobGroup, int jobId, int type) { + + Date clearBeforeTime = null; + int clearBeforeNum = 0; + if (type == 1) { + clearBeforeTime = DateUtil.addMonths(new Date(), -1); // 清理一个月之前日志数据 + } else if (type == 2) { + clearBeforeTime = DateUtil.addMonths(new Date(), -3); // 清理三个月之前日志数据 + } else if (type == 3) { + clearBeforeTime = DateUtil.addMonths(new Date(), -6); // 清理六个月之前日志数据 + } else if (type == 4) { + clearBeforeTime = DateUtil.addYears(new Date(), -1); // 清理一年之前日志数据 + } else if (type == 5) { + clearBeforeNum = 1000; // 清理一千条以前日志数据 + } else if (type == 6) { + clearBeforeNum = 10000; // 清理一万条以前日志数据 + } else if (type == 7) { + clearBeforeNum = 30000; // 清理三万条以前日志数据 + } else if (type == 8) { + clearBeforeNum = 100000; // 清理十万条以前日志数据 + } else if (type == 9) { + clearBeforeNum = 0; // 清理所有日志数据 + } else { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid")); + } + + List logIds = null; + do { + logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000); + if (logIds != null && logIds.size() > 0) { + xxlJobLogDao.clearLog(logIds); + } + } while (logIds != null && logIds.size() > 0); + + return ReturnT.SUCCESS; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java new file mode 100644 index 0000000..8889c79 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java @@ -0,0 +1,179 @@ +package com.xxl.job.admin.controller; + +import com.xxl.job.admin.controller.annotation.PermissionLimit; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobUser; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.dao.XxlJobGroupDao; +import com.xxl.job.admin.dao.XxlJobUserDao; +import com.xxl.job.admin.service.LoginService; +import com.xxl.job.core.biz.model.ReturnT; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.util.DigestUtils; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author xuxueli 2019-05-04 16:39:50 + */ +@Controller +@RequestMapping("/user") +public class UserController { + + @Resource + private XxlJobUserDao xxlJobUserDao; + @Resource + private XxlJobGroupDao xxlJobGroupDao; + + @RequestMapping + @PermissionLimit(adminuser = true) + public String index(Model model) { + + // 执行器列表 + List groupList = xxlJobGroupDao.findAll(); + model.addAttribute("groupList", groupList); + + return "user/user.index"; + } + + @RequestMapping("/pageList") + @ResponseBody + @PermissionLimit(adminuser = true) + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String username, int role) { + + // page list + List list = xxlJobUserDao.pageList(start, length, username, role); + int list_count = xxlJobUserDao.pageListCount(start, length, username, role); + + // filter + if (list != null && list.size() > 0) { + for (XxlJobUser item : list) { + item.setPassword(null); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + @PermissionLimit(adminuser = true) + public ReturnT add(XxlJobUser xxlJobUser) { + + // valid username + if (!StringUtils.hasText(xxlJobUser.getUsername())) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_username")); + } + xxlJobUser.setUsername(xxlJobUser.getUsername().trim()); + if (!(xxlJobUser.getUsername().length() >= 4 && xxlJobUser.getUsername().length() <= 20)) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); + } + // valid password + if (!StringUtils.hasText(xxlJobUser.getPassword())) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_password")); + } + xxlJobUser.setPassword(xxlJobUser.getPassword().trim()); + if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); + } + // md5 password + xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes())); + + // check repeat + XxlJobUser existUser = xxlJobUserDao.loadByUserName(xxlJobUser.getUsername()); + if (existUser != null) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat")); + } + + // write + xxlJobUserDao.save(xxlJobUser); + return ReturnT.SUCCESS; + } + + @RequestMapping("/update") + @ResponseBody + @PermissionLimit(adminuser = true) + public ReturnT update(HttpServletRequest request, XxlJobUser xxlJobUser) { + + // avoid opt login seft + XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY); + if (loginUser.getUsername().equals(xxlJobUser.getUsername())) { + return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit")); + } + + // valid password + if (StringUtils.hasText(xxlJobUser.getPassword())) { + xxlJobUser.setPassword(xxlJobUser.getPassword().trim()); + if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); + } + // md5 password + xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes())); + } else { + xxlJobUser.setPassword(null); + } + + // write + xxlJobUserDao.update(xxlJobUser); + return ReturnT.SUCCESS; + } + + @RequestMapping("/remove") + @ResponseBody + @PermissionLimit(adminuser = true) + public ReturnT remove(HttpServletRequest request, int id) { + + // avoid opt login seft + XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY); + if (loginUser.getId() == id) { + return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit")); + } + + xxlJobUserDao.delete(id); + return ReturnT.SUCCESS; + } + + @RequestMapping("/updatePwd") + @ResponseBody + public ReturnT updatePwd(HttpServletRequest request, String password) { + + // valid password + if (password == null || password.trim().length() == 0) { + return new ReturnT(ReturnT.FAIL.getCode(), "密码不可为空"); + } + password = password.trim(); + if (!(password.length() >= 4 && password.length() <= 20)) { + return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]"); + } + + // md5 password + String md5Password = DigestUtils.md5DigestAsHex(password.getBytes()); + + // update pwd + XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY); + + // do write + XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername()); + existUser.setPassword(md5Password); + xxlJobUserDao.update(existUser); + + return ReturnT.SUCCESS; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java new file mode 100644 index 0000000..054d6ef --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java @@ -0,0 +1,30 @@ +package com.xxl.job.admin.controller.annotation; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 权限限制 + * + * @author xuxueli 2015-12-12 18:29:02 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface PermissionLimit { + + /** + * 登录拦截 (默认拦截) + */ + boolean limit() default true; + + /** + * 要求管理员权限 + * + * @return + */ + boolean adminuser() default false; + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java new file mode 100644 index 0000000..2283849 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java @@ -0,0 +1,42 @@ +package com.xxl.job.admin.controller.interceptor; + +import com.xxl.job.admin.core.util.FtlUtil; +import com.xxl.job.admin.core.util.I18nUtil; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.AsyncHandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; + +/** + * push cookies to model as cookieMap + * + * @author xuxueli 2015-12-12 18:09:04 + */ +@Component +public class CookieInterceptor implements AsyncHandlerInterceptor { + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + + // cookie + if (modelAndView != null && request.getCookies() != null && request.getCookies().length > 0) { + HashMap cookieMap = new HashMap(); + for (Cookie ck : request.getCookies()) { + cookieMap.put(ck.getName(), ck); + } + modelAndView.addObject("cookieMap", cookieMap); + } + + // static method + if (modelAndView != null) { + modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName())); + } + + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java new file mode 100644 index 0000000..13e53b2 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java @@ -0,0 +1,59 @@ +package com.xxl.job.admin.controller.interceptor; + +import com.xxl.job.admin.controller.annotation.PermissionLimit; +import com.xxl.job.admin.core.model.XxlJobUser; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.service.LoginService; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.AsyncHandlerInterceptor; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 权限拦截 + * + * @author xuxueli 2015-12-12 18:09:04 + */ +@Component +public class PermissionInterceptor implements AsyncHandlerInterceptor { + + @Resource + private LoginService loginService; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + + if (!(handler instanceof HandlerMethod)) { + return true; // proceed with the next interceptor + } + + // if need login + boolean needLogin = true; + boolean needAdminuser = false; + HandlerMethod method = (HandlerMethod) handler; + PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class); + if (permission != null) { + needLogin = permission.limit(); + needAdminuser = permission.adminuser(); + } + + if (needLogin) { + XxlJobUser loginUser = loginService.ifLogin(request, response); + if (loginUser == null) { + response.setStatus(302); + response.setHeader("location", request.getContextPath() + "/toLogin"); + return false; + } + if (needAdminuser && loginUser.getRole() != 1) { + throw new RuntimeException(I18nUtil.getString("system_permission_limit")); + } + request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser); + } + + return true; // proceed with the next interceptor + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java new file mode 100644 index 0000000..0be6ba6 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java @@ -0,0 +1,28 @@ +package com.xxl.job.admin.controller.interceptor; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import javax.annotation.Resource; + +/** + * web mvc config + * + * @author xuxueli 2018-04-02 20:48:20 + */ +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Resource + private PermissionInterceptor permissionInterceptor; + @Resource + private CookieInterceptor cookieInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(permissionInterceptor).addPathPatterns("/**"); + registry.addInterceptor(cookieInterceptor).addPathPatterns("/**"); + } + +} \ No newline at end of file diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java new file mode 100644 index 0000000..d7cc0db --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java @@ -0,0 +1,66 @@ +package com.xxl.job.admin.controller.resolver; + +import com.xxl.job.admin.core.exception.XxlJobException; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.admin.core.util.JacksonUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExceptionResolver; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * common exception resolver + * + * @author xuxueli 2016-1-6 19:22:18 + */ +@Component +public class WebExceptionResolver implements HandlerExceptionResolver { + private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class); + + @Override + public ModelAndView resolveException(HttpServletRequest request, + HttpServletResponse response, Object handler, Exception ex) { + + if (!(ex instanceof XxlJobException)) { + logger.error("WebExceptionResolver:{}", ex); + } + + // if json + boolean isJson = false; + if (handler instanceof HandlerMethod) { + HandlerMethod method = (HandlerMethod) handler; + ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); + if (responseBody != null) { + isJson = true; + } + } + + // error result + ReturnT errorResult = new ReturnT(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "
")); + + // response + ModelAndView mv = new ModelAndView(); + if (isJson) { + try { + response.setContentType("application/json;charset=utf-8"); + response.getWriter().print(JacksonUtil.writeValueAsString(errorResult)); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return mv; + } else { + + mv.addObject("exceptionMsg", errorResult.getMsg()); + mv.setViewName("/common/common.exception"); + return mv; + } + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java new file mode 100644 index 0000000..4165ff3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java @@ -0,0 +1,20 @@ +package com.xxl.job.admin.core.alarm; + +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; + +/** + * @author xuxueli 2020-01-19 + */ +public interface JobAlarm { + + /** + * job alarm + * + * @param info + * @param jobLog + * @return + */ + public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java new file mode 100644 index 0000000..62dac9d --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java @@ -0,0 +1,65 @@ +package com.xxl.job.admin.core.alarm; + +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Component +public class JobAlarmer implements ApplicationContextAware, InitializingBean { + private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class); + + private ApplicationContext applicationContext; + private List jobAlarmList; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; + } + + @Override + public void afterPropertiesSet() throws Exception { + Map serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class); + if (serviceBeanMap != null && serviceBeanMap.size() > 0) { + jobAlarmList = new ArrayList(serviceBeanMap.values()); + } + } + + /** + * job alarm + * + * @param info + * @param jobLog + * @return + */ + public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) { + + boolean result = false; + if (jobAlarmList != null && jobAlarmList.size() > 0) { + result = true; // success means all-success + for (JobAlarm alarm : jobAlarmList) { + boolean resultItem = false; + try { + resultItem = alarm.doAlarm(info, jobLog); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + if (!resultItem) { + result = false; + } + } + } + + return result; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java new file mode 100644 index 0000000..6ad1c0b --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java @@ -0,0 +1,118 @@ +package com.xxl.job.admin.core.alarm.impl; + +import com.xxl.job.admin.core.alarm.JobAlarm; +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.model.ReturnT; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; + +import javax.mail.internet.MimeMessage; +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * job alarm by email + * + * @author xuxueli 2020-01-19 + */ +@Component +public class EmailJobAlarm implements JobAlarm { + private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class); + + /** + * fail alarm + * + * @param jobLog + */ + @Override + public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog) { + boolean alarmResult = true; + + // send monitor email + if (info != null && info.getAlarmEmail() != null && info.getAlarmEmail().trim().length() > 0) { + + // alarmContent + String alarmContent = "Alarm Job LogId=" + jobLog.getId(); + if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) { + alarmContent += "
TriggerMsg=
" + jobLog.getTriggerMsg(); + } + if (jobLog.getHandleCode() > 0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) { + alarmContent += "
HandleCode=" + jobLog.getHandleMsg(); + } + + // email info + XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup())); + String personal = I18nUtil.getString("admin_name_full"); + String title = I18nUtil.getString("jobconf_monitor"); + String content = MessageFormat.format(loadEmailJobAlarmTemplate(), + group != null ? group.getTitle() : "null", + info.getId(), + info.getJobDesc(), + alarmContent); + + Set emailSet = new HashSet(Arrays.asList(info.getAlarmEmail().split(","))); + for (String email : emailSet) { + + // make mail + try { + MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage(); + + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailFrom(), personal); + helper.setTo(email); + helper.setSubject(title); + helper.setText(content, true); + + XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage); + } catch (Exception e) { + logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e); + + alarmResult = false; + } + + } + } + + return alarmResult; + } + + /** + * load email job alarm template + * + * @return + */ + private static final String loadEmailJobAlarmTemplate() { + String mailBodyTemplate = "

" + I18nUtil.getString("jobconf_monitor_detail") + ":" + + "\n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
" + I18nUtil.getString("jobinfo_field_jobgroup") + "" + I18nUtil.getString("jobinfo_field_id") + "" + I18nUtil.getString("jobinfo_field_jobdesc") + "" + I18nUtil.getString("jobconf_monitor_alarm_title") + "" + I18nUtil.getString("jobconf_monitor_alarm_content") + "
{0}{1}{2}" + I18nUtil.getString("jobconf_monitor_alarm_type") + "{3}
"; + + return mailBodyTemplate; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java new file mode 100644 index 0000000..8339933 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java @@ -0,0 +1,99 @@ +package com.xxl.job.admin.core.complete; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; +import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; +import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.context.XxlJobContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; + +/** + * @author xuxueli 2020-10-30 20:43:10 + */ +public class XxlJobCompleter { + private static Logger logger = LoggerFactory.getLogger(XxlJobCompleter.class); + + /** + * common fresh handle entrance (limit only once) + * + * @param xxlJobLog + * @return + */ + public static int updateHandleInfoAndFinish(XxlJobLog xxlJobLog) { + + // finish + finishJob(xxlJobLog); + + // text最大64kb 避免长度过长 + if (xxlJobLog.getHandleMsg().length() > 15000) { + xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 15000)); + } + + // fresh handle + return XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(xxlJobLog); + } + + + /** + * do somethind to finish job + */ + private static void finishJob(XxlJobLog xxlJobLog) { + + // 1、handle success, to trigger child job + String triggerChildMsg = null; + if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) { + XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(xxlJobLog.getJobId()); + if (xxlJobInfo != null && xxlJobInfo.getChildJobId() != null && xxlJobInfo.getChildJobId().trim().length() > 0) { + triggerChildMsg = "

>>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<<
"; + + String[] childJobIds = xxlJobInfo.getChildJobId().split(","); + for (int i = 0; i < childJobIds.length; i++) { + int childJobId = (childJobIds[i] != null && childJobIds[i].trim().length() > 0 && isNumeric(childJobIds[i])) ? Integer.valueOf(childJobIds[i]) : -1; + if (childJobId > 0) { + + JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null); + ReturnT triggerChildResult = ReturnT.SUCCESS; + + // add msg + triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"), + (i + 1), + childJobIds.length, + childJobIds[i], + (triggerChildResult.getCode() == ReturnT.SUCCESS_CODE ? I18nUtil.getString("system_success") : I18nUtil.getString("system_fail")), + triggerChildResult.getMsg()); + } else { + triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"), + (i + 1), + childJobIds.length, + childJobIds[i]); + } + } + + } + } + + if (triggerChildMsg != null) { + xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg() + triggerChildMsg); + } + + // 2、fix_delay trigger next + // on the way + + } + + private static boolean isNumeric(String str) { + try { + int result = Integer.valueOf(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java new file mode 100644 index 0000000..6e40cb7 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java @@ -0,0 +1,159 @@ +package com.xxl.job.admin.core.conf; + +import com.xxl.job.admin.core.alarm.JobAlarmer; +import com.xxl.job.admin.core.scheduler.XxlJobScheduler; +import com.xxl.job.admin.dao.*; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import javax.sql.DataSource; +import java.util.Arrays; + +/** + * xxl-job config + * + * @author xuxueli 2017-04-28 + */ + +@Component +public class XxlJobAdminConfig implements InitializingBean, DisposableBean { + + private static XxlJobAdminConfig adminConfig = null; + + public static XxlJobAdminConfig getAdminConfig() { + return adminConfig; + } + + + // ---------------------- XxlJobScheduler ---------------------- + + private XxlJobScheduler xxlJobScheduler; + + @Override + public void afterPropertiesSet() throws Exception { + adminConfig = this; + + xxlJobScheduler = new XxlJobScheduler(); + xxlJobScheduler.init(); + } + + @Override + public void destroy() throws Exception { + xxlJobScheduler.destroy(); + } + + + // ---------------------- XxlJobScheduler ---------------------- + + // conf + @Value("${xxl.job.i18n}") + private String i18n; + + @Value("${xxl.job.accessToken}") + private String accessToken; + + @Value("${spring.mail.from}") + private String emailFrom; + + @Value("${xxl.job.triggerpool.fast.max}") + private int triggerPoolFastMax; + + @Value("${xxl.job.triggerpool.slow.max}") + private int triggerPoolSlowMax; + + @Value("${xxl.job.logretentiondays}") + private int logretentiondays; + + // dao, service + + @Resource + private XxlJobLogDao xxlJobLogDao; + @Resource + private XxlJobInfoDao xxlJobInfoDao; + @Resource + private XxlJobRegistryDao xxlJobRegistryDao; + @Resource + private XxlJobGroupDao xxlJobGroupDao; + @Resource + private XxlJobLogReportDao xxlJobLogReportDao; + @Resource + private JavaMailSender mailSender; + @Resource + private DataSource dataSource; + @Resource + private JobAlarmer jobAlarmer; + + + public String getI18n() { + if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) { + return "zh_CN"; + } + return i18n; + } + + public String getAccessToken() { + return accessToken; + } + + public String getEmailFrom() { + return emailFrom; + } + + public int getTriggerPoolFastMax() { + if (triggerPoolFastMax < 200) { + return 200; + } + return triggerPoolFastMax; + } + + public int getTriggerPoolSlowMax() { + if (triggerPoolSlowMax < 100) { + return 100; + } + return triggerPoolSlowMax; + } + + public int getLogretentiondays() { + if (logretentiondays < 7) { + return -1; // Limit greater than or equal to 7, otherwise close + } + return logretentiondays; + } + + public XxlJobLogDao getXxlJobLogDao() { + return xxlJobLogDao; + } + + public XxlJobInfoDao getXxlJobInfoDao() { + return xxlJobInfoDao; + } + + public XxlJobRegistryDao getXxlJobRegistryDao() { + return xxlJobRegistryDao; + } + + public XxlJobGroupDao getXxlJobGroupDao() { + return xxlJobGroupDao; + } + + public XxlJobLogReportDao getXxlJobLogReportDao() { + return xxlJobLogReportDao; + } + + public JavaMailSender getMailSender() { + return mailSender; + } + + public DataSource getDataSource() { + return dataSource; + } + + public JobAlarmer getJobAlarmer() { + return jobAlarmer; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java new file mode 100644 index 0000000..2ce373e --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java @@ -0,0 +1,1677 @@ +/* + * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + */ + +package com.xxl.job.admin.core.cron; + +import java.io.Serializable; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.SortedSet; +import java.util.StringTokenizer; +import java.util.TimeZone; +import java.util.TreeSet; + +/** + * Provides a parser and evaluator for unix-like cron expressions. Cron + * expressions provide the ability to specify complex time combinations such as + * "At 8:00am every Monday through Friday" or "At 1:30am every + * last Friday of the month". + *

+ * Cron expressions are comprised of 6 required fields and one optional field + * separated by white space. The fields respectively are described as follows: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Field Name Allowed Values Allowed Special Characters
Seconds  + * 0-59  + * , - * /
Minutes  + * 0-59  + * , - * /
Hours  + * 0-23  + * , - * /
Day-of-month  + * 1-31  + * , - * ? / L W
Month  + * 0-11 or JAN-DEC  + * , - * /
Day-of-Week  + * 1-7 or SUN-SAT  + * , - * ? / L #
Year (Optional)  + * empty, 1970-2199  + * , - * /
+ *

+ * The '*' character is used to specify all values. For example, "*" + * in the minute field means "every minute". + *

+ * The '?' character is allowed for the day-of-month and day-of-week fields. It + * is used to specify 'no specific value'. This is useful when you need to + * specify something in one of the two fields, but not the other. + *

+ * The '-' character is used to specify ranges For example "10-12" in + * the hour field means "the hours 10, 11 and 12". + *

+ * The ',' character is used to specify additional values. For example + * "MON,WED,FRI" in the day-of-week field means "the days Monday, + * Wednesday, and Friday". + *

+ * The '/' character is used to specify increments. For example "0/15" + * in the seconds field means "the seconds 0, 15, 30, and 45". And + * "5/15" in the seconds field means "the seconds 5, 20, 35, and + * 50". Specifying '*' before the '/' is equivalent to specifying 0 is + * the value to start with. Essentially, for each field in the expression, there + * is a set of numbers that can be turned on or off. For seconds and minutes, + * the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to + * 31, and for months 0 to 11 (JAN to DEC). The "/" character simply helps you turn + * on every "nth" value in the given set. Thus "7/6" in the + * month field only turns on month "7", it does NOT mean every 6th + * month, please note that subtlety. + *

+ * The 'L' character is allowed for the day-of-month and day-of-week fields. + * This character is short-hand for "last", but it has different + * meaning in each of the two fields. For example, the value "L" in + * the day-of-month field means "the last day of the month" - day 31 + * for January, day 28 for February on non-leap years. If used in the + * day-of-week field by itself, it simply means "7" or + * "SAT". But if used in the day-of-week field after another value, it + * means "the last xxx day of the month" - for example "6L" + * means "the last friday of the month". You can also specify an offset + * from the last day of the month, such as "L-3" which would mean the third-to-last + * day of the calendar month. When using the 'L' option, it is important not to + * specify lists, or ranges of values, as you'll get confusing/unexpected results. + *

+ * The 'W' character is allowed for the day-of-month field. This character + * is used to specify the weekday (Monday-Friday) nearest the given day. As an + * example, if you were to specify "15W" as the value for the + * day-of-month field, the meaning is: "the nearest weekday to the 15th of + * the month". So if the 15th is a Saturday, the trigger will fire on + * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the + * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th. + * However if you specify "1W" as the value for day-of-month, and the + * 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not + * 'jump' over the boundary of a month's days. The 'W' character can only be + * specified when the day-of-month is a single day, not a range or list of days. + *

+ * The 'L' and 'W' characters can also be combined for the day-of-month + * expression to yield 'LW', which translates to "last weekday of the + * month". + *

+ * The '#' character is allowed for the day-of-week field. This character is + * used to specify "the nth" XXX day of the month. For example, the + * value of "6#3" in the day-of-week field means the third Friday of + * the month (day 6 = Friday and "#3" = the 3rd one in the month). + * Other examples: "2#1" = the first Monday of the month and + * "4#5" = the fifth Wednesday of the month. Note that if you specify + * "#5" and there is not 5 of the given day-of-week in the month, then + * no firing will occur that month. If the '#' character is used, there can + * only be one expression in the day-of-week field ("3#1,6#3" is + * not valid, since there are two expressions). + *

+ * + *

+ * The legal characters and the names of months and days of the week are not + * case sensitive. + * + *

+ * NOTES: + *

    + *
  • Support for specifying both a day-of-week and a day-of-month value is + * not complete (you'll need to use the '?' character in one of these fields). + *
  • + *
  • Overflowing ranges is supported - that is, having a larger number on + * the left hand side than the right. You might do 22-2 to catch 10 o'clock + * at night until 2 o'clock in the morning, or you might have NOV-FEB. It is + * very important to note that overuse of overflowing ranges creates ranges + * that don't make sense and no effort has been made to determine which + * interpretation CronExpression chooses. An example would be + * "0 0 14-6 ? * FRI-MON".
  • + *
+ *

+ * + * @author Sharada Jambula, James House + * @author Contributions from Mads Henderson + * @author Refactoring from CronTrigger to CronExpression by Aaron Craven + *

+ * Borrowed from quartz v2.3.1 + */ +public final class CronExpression implements Serializable, Cloneable { + + private static final long serialVersionUID = 12423409423L; + + protected static final int SECOND = 0; + protected static final int MINUTE = 1; + protected static final int HOUR = 2; + protected static final int DAY_OF_MONTH = 3; + protected static final int MONTH = 4; + protected static final int DAY_OF_WEEK = 5; + protected static final int YEAR = 6; + protected static final int ALL_SPEC_INT = 99; // '*' + protected static final int NO_SPEC_INT = 98; // '?' + protected static final Integer ALL_SPEC = ALL_SPEC_INT; + protected static final Integer NO_SPEC = NO_SPEC_INT; + + protected static final Map monthMap = new HashMap(20); + protected static final Map dayMap = new HashMap(60); + + static { + monthMap.put("JAN", 0); + monthMap.put("FEB", 1); + monthMap.put("MAR", 2); + monthMap.put("APR", 3); + monthMap.put("MAY", 4); + monthMap.put("JUN", 5); + monthMap.put("JUL", 6); + monthMap.put("AUG", 7); + monthMap.put("SEP", 8); + monthMap.put("OCT", 9); + monthMap.put("NOV", 10); + monthMap.put("DEC", 11); + + dayMap.put("SUN", 1); + dayMap.put("MON", 2); + dayMap.put("TUE", 3); + dayMap.put("WED", 4); + dayMap.put("THU", 5); + dayMap.put("FRI", 6); + dayMap.put("SAT", 7); + } + + private final String cronExpression; + private TimeZone timeZone = null; + protected transient TreeSet seconds; + protected transient TreeSet minutes; + protected transient TreeSet hours; + protected transient TreeSet daysOfMonth; + protected transient TreeSet months; + protected transient TreeSet daysOfWeek; + protected transient TreeSet years; + + protected transient boolean lastdayOfWeek = false; + protected transient int nthdayOfWeek = 0; + protected transient boolean lastdayOfMonth = false; + protected transient boolean nearestWeekday = false; + protected transient int lastdayOffset = 0; + protected transient boolean expressionParsed = false; + + public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100; + + /** + * Constructs a new CronExpression based on the specified + * parameter. + * + * @param cronExpression String representation of the cron expression the + * new object should represent + * @throws ParseException if the string expression cannot be parsed into a valid + * CronExpression + */ + public CronExpression(String cronExpression) throws ParseException { + if (cronExpression == null) { + throw new IllegalArgumentException("cronExpression cannot be null"); + } + + this.cronExpression = cronExpression.toUpperCase(Locale.US); + + buildExpression(this.cronExpression); + } + + /** + * Constructs a new {@code CronExpression} as a copy of an existing + * instance. + * + * @param expression The existing cron expression to be copied + */ + public CronExpression(CronExpression expression) { + /* + * We don't call the other constructor here since we need to swallow the + * ParseException. We also elide some of the sanity checking as it is + * not logically trippable. + */ + this.cronExpression = expression.getCronExpression(); + try { + buildExpression(cronExpression); + } catch (ParseException ex) { + throw new AssertionError(); + } + if (expression.getTimeZone() != null) { + setTimeZone((TimeZone) expression.getTimeZone().clone()); + } + } + + /** + * Indicates whether the given date satisfies the cron expression. Note that + * milliseconds are ignored, so two Dates falling on different milliseconds + * of the same second will always have the same result here. + * + * @param date the date to evaluate + * @return a boolean indicating whether the given date satisfies the cron + * expression + */ + public boolean isSatisfiedBy(Date date) { + Calendar testDateCal = Calendar.getInstance(getTimeZone()); + testDateCal.setTime(date); + testDateCal.set(Calendar.MILLISECOND, 0); + Date originalDate = testDateCal.getTime(); + + testDateCal.add(Calendar.SECOND, -1); + + Date timeAfter = getTimeAfter(testDateCal.getTime()); + + return ((timeAfter != null) && (timeAfter.equals(originalDate))); + } + + /** + * Returns the next date/time after the given date/time which + * satisfies the cron expression. + * + * @param date the date/time at which to begin the search for the next valid + * date/time + * @return the next valid date/time + */ + public Date getNextValidTimeAfter(Date date) { + return getTimeAfter(date); + } + + /** + * Returns the next date/time after the given date/time which does + * not satisfy the expression + * + * @param date the date/time at which to begin the search for the next + * invalid date/time + * @return the next valid date/time + */ + public Date getNextInvalidTimeAfter(Date date) { + long difference = 1000; + + //move back to the nearest second so differences will be accurate + Calendar adjustCal = Calendar.getInstance(getTimeZone()); + adjustCal.setTime(date); + adjustCal.set(Calendar.MILLISECOND, 0); + Date lastDate = adjustCal.getTime(); + + Date newDate; + + //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution. + + //keep getting the next included time until it's farther than one second + // apart. At that point, lastDate is the last valid fire time. We return + // the second immediately following it. + while (difference == 1000) { + newDate = getTimeAfter(lastDate); + if (newDate == null) + break; + + difference = newDate.getTime() - lastDate.getTime(); + + if (difference == 1000) { + lastDate = newDate; + } + } + + return new Date(lastDate.getTime() + 1000); + } + + /** + * Returns the time zone for which this CronExpression + * will be resolved. + */ + public TimeZone getTimeZone() { + if (timeZone == null) { + timeZone = TimeZone.getDefault(); + } + + return timeZone; + } + + /** + * Sets the time zone for which this CronExpression + * will be resolved. + */ + public void setTimeZone(TimeZone timeZone) { + this.timeZone = timeZone; + } + + /** + * Returns the string representation of the CronExpression + * + * @return a string representation of the CronExpression + */ + @Override + public String toString() { + return cronExpression; + } + + /** + * Indicates whether the specified cron expression can be parsed into a + * valid cron expression + * + * @param cronExpression the expression to evaluate + * @return a boolean indicating whether the given expression is a valid cron + * expression + */ + public static boolean isValidExpression(String cronExpression) { + + try { + new CronExpression(cronExpression); + } catch (ParseException pe) { + return false; + } + + return true; + } + + public static void validateExpression(String cronExpression) throws ParseException { + + new CronExpression(cronExpression); + } + + + //////////////////////////////////////////////////////////////////////////// + // + // Expression Parsing Functions + // + //////////////////////////////////////////////////////////////////////////// + + protected void buildExpression(String expression) throws ParseException { + expressionParsed = true; + + try { + + if (seconds == null) { + seconds = new TreeSet(); + } + if (minutes == null) { + minutes = new TreeSet(); + } + if (hours == null) { + hours = new TreeSet(); + } + if (daysOfMonth == null) { + daysOfMonth = new TreeSet(); + } + if (months == null) { + months = new TreeSet(); + } + if (daysOfWeek == null) { + daysOfWeek = new TreeSet(); + } + if (years == null) { + years = new TreeSet(); + } + + int exprOn = SECOND; + + StringTokenizer exprsTok = new StringTokenizer(expression, " \t", + false); + + while (exprsTok.hasMoreTokens() && exprOn <= YEAR) { + String expr = exprsTok.nextToken().trim(); + + // throw an exception if L is used with other days of the month + if (exprOn == DAY_OF_MONTH && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' and 'LW' with other days of the month is not implemented", -1); + } + // throw an exception if L is used with other days of the week + if (exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) { + throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1); + } + if (exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') + 1) != -1) { + throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1); + } + + StringTokenizer vTok = new StringTokenizer(expr, ","); + while (vTok.hasMoreTokens()) { + String v = vTok.nextToken(); + storeExpressionVals(0, v, exprOn); + } + + exprOn++; + } + + if (exprOn <= DAY_OF_WEEK) { + throw new ParseException("Unexpected end of expression.", + expression.length()); + } + + if (exprOn <= YEAR) { + storeExpressionVals(0, "*", YEAR); + } + + TreeSet dow = getSet(DAY_OF_WEEK); + TreeSet dom = getSet(DAY_OF_MONTH); + + // Copying the logic from the UnsupportedOperationException below + boolean dayOfMSpec = !dom.contains(NO_SPEC); + boolean dayOfWSpec = !dow.contains(NO_SPEC); + + if (!dayOfMSpec || dayOfWSpec) { + if (!dayOfWSpec || dayOfMSpec) { + throw new ParseException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0); + } + } + } catch (ParseException pe) { + throw pe; + } catch (Exception e) { + throw new ParseException("Illegal cron expression format (" + + e.toString() + ")", 0); + } + } + + protected int storeExpressionVals(int pos, String s, int type) + throws ParseException { + + int incr = 0; + int i = skipWhiteSpace(pos, s); + if (i >= s.length()) { + return i; + } + char c = s.charAt(i); + if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) { + String sub = s.substring(i, i + 3); + int sval = -1; + int eval = -1; + if (type == MONTH) { + sval = getMonthNumber(sub) + 1; + if (sval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } + if (s.length() > i + 3) { + c = s.charAt(i + 3); + if (c == '-') { + i += 4; + sub = s.substring(i, i + 3); + eval = getMonthNumber(sub) + 1; + if (eval <= 0) { + throw new ParseException("Invalid Month value: '" + sub + "'", i); + } + } + } + } else if (type == DAY_OF_WEEK) { + sval = getDayOfWeekNumber(sub); + if (sval < 0) { + throw new ParseException("Invalid Day-of-Week value: '" + + sub + "'", i); + } + if (s.length() > i + 3) { + c = s.charAt(i + 3); + if (c == '-') { + i += 4; + sub = s.substring(i, i + 3); + eval = getDayOfWeekNumber(sub); + if (eval < 0) { + throw new ParseException( + "Invalid Day-of-Week value: '" + sub + + "'", i); + } + } else if (c == '#') { + try { + i += 4; + nthdayOfWeek = Integer.parseInt(s.substring(i)); + if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { + throw new Exception(); + } + } catch (Exception e) { + throw new ParseException( + "A numeric value between 1 and 5 must follow the '#' option", + i); + } + } else if (c == 'L') { + lastdayOfWeek = true; + i++; + } + } + + } else { + throw new ParseException( + "Illegal characters for this position: '" + sub + "'", + i); + } + if (eval != -1) { + incr = 1; + } + addToSet(sval, eval, incr, type); + return (i + 3); + } + + if (c == '?') { + i++; + if ((i + 1) < s.length() + && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) { + throw new ParseException("Illegal character after '?': " + + s.charAt(i), i); + } + if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) { + throw new ParseException( + "'?' can only be specified for Day-of-Month or Day-of-Week.", + i); + } + if (type == DAY_OF_WEEK && !lastdayOfMonth) { + int val = daysOfMonth.last(); + if (val == NO_SPEC_INT) { + throw new ParseException( + "'?' can only be specified for Day-of-Month -OR- Day-of-Week.", + i); + } + } + + addToSet(NO_SPEC_INT, -1, 0, type); + return i; + } + + if (c == '*' || c == '/') { + if (c == '*' && (i + 1) >= s.length()) { + addToSet(ALL_SPEC_INT, -1, incr, type); + return i + 1; + } else if (c == '/' + && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s + .charAt(i + 1) == '\t')) { + throw new ParseException("'/' must be followed by an integer.", i); + } else if (c == '*') { + i++; + } + c = s.charAt(i); + if (c == '/') { // is an increment specified? + i++; + if (i >= s.length()) { + throw new ParseException("Unexpected end of string.", i); + } + + incr = getNumericValue(s, i); + + i++; + if (incr > 10) { + i++; + } + checkIncrementRange(incr, type, i); + } else { + incr = 1; + } + + addToSet(ALL_SPEC_INT, -1, incr, type); + return i; + } else if (c == 'L') { + i++; + if (type == DAY_OF_MONTH) { + lastdayOfMonth = true; + } + if (type == DAY_OF_WEEK) { + addToSet(7, 7, 0, type); + } + if (type == DAY_OF_MONTH && s.length() > i) { + c = s.charAt(i); + if (c == '-') { + ValueSet vs = getValue(0, s, i + 1); + lastdayOffset = vs.value; + if (lastdayOffset > 30) + throw new ParseException("Offset from last day must be <= 30", i + 1); + i = vs.pos; + } + if (s.length() > i) { + c = s.charAt(i); + if (c == 'W') { + nearestWeekday = true; + i++; + } + } + } + return i; + } else if (c >= '0' && c <= '9') { + int val = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + addToSet(val, -1, -1, type); + } else { + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(val, s, i); + val = vs.value; + i = vs.pos; + } + i = checkNext(i, s, val, type); + return i; + } + } else { + throw new ParseException("Unexpected character: " + c, i); + } + + return i; + } + + private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException { + if (incr > 59 && (type == SECOND || type == MINUTE)) { + throw new ParseException("Increment > 60 : " + incr, idxPos); + } else if (incr > 23 && (type == HOUR)) { + throw new ParseException("Increment > 24 : " + incr, idxPos); + } else if (incr > 31 && (type == DAY_OF_MONTH)) { + throw new ParseException("Increment > 31 : " + incr, idxPos); + } else if (incr > 7 && (type == DAY_OF_WEEK)) { + throw new ParseException("Increment > 7 : " + incr, idxPos); + } else if (incr > 12 && (type == MONTH)) { + throw new ParseException("Increment > 12 : " + incr, idxPos); + } + } + + protected int checkNext(int pos, String s, int val, int type) + throws ParseException { + + int end = -1; + int i = pos; + + if (i >= s.length()) { + addToSet(val, end, -1, type); + return i; + } + + char c = s.charAt(pos); + + if (c == 'L') { + if (type == DAY_OF_WEEK) { + if (val < 1 || val > 7) + throw new ParseException("Day-of-Week values must be between 1 and 7", -1); + lastdayOfWeek = true; + } else { + throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i); + } + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == 'W') { + if (type == DAY_OF_MONTH) { + nearestWeekday = true; + } else { + throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i); + } + if (val > 31) + throw new ParseException("The 'W' option does not make sense with values larger than 31 (max number of days in a month)", i); + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == '#') { + if (type != DAY_OF_WEEK) { + throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i); + } + i++; + try { + nthdayOfWeek = Integer.parseInt(s.substring(i)); + if (nthdayOfWeek < 1 || nthdayOfWeek > 5) { + throw new Exception(); + } + } catch (Exception e) { + throw new ParseException( + "A numeric value between 1 and 5 must follow the '#' option", + i); + } + + TreeSet set = getSet(type); + set.add(val); + i++; + return i; + } + + if (c == '-') { + i++; + c = s.charAt(i); + int v = Integer.parseInt(String.valueOf(c)); + end = v; + i++; + if (i >= s.length()) { + addToSet(val, end, 1, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v, s, i); + end = vs.value; + i = vs.pos; + } + if (i < s.length() && ((c = s.charAt(i)) == '/')) { + i++; + c = s.charAt(i); + int v2 = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + addToSet(val, end, v2, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v2, s, i); + int v3 = vs.value; + addToSet(val, end, v3, type); + i = vs.pos; + return i; + } else { + addToSet(val, end, v2, type); + return i; + } + } else { + addToSet(val, end, 1, type); + return i; + } + } + + if (c == '/') { + if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t') { + throw new ParseException("'/' must be followed by an integer.", i); + } + + i++; + c = s.charAt(i); + int v2 = Integer.parseInt(String.valueOf(c)); + i++; + if (i >= s.length()) { + checkIncrementRange(v2, type, i); + addToSet(val, end, v2, type); + return i; + } + c = s.charAt(i); + if (c >= '0' && c <= '9') { + ValueSet vs = getValue(v2, s, i); + int v3 = vs.value; + checkIncrementRange(v3, type, i); + addToSet(val, end, v3, type); + i = vs.pos; + return i; + } else { + throw new ParseException("Unexpected character '" + c + "' after '/'", i); + } + } + + addToSet(val, end, 0, type); + i++; + return i; + } + + public String getCronExpression() { + return cronExpression; + } + + public String getExpressionSummary() { + StringBuilder buf = new StringBuilder(); + + buf.append("seconds: "); + buf.append(getExpressionSetSummary(seconds)); + buf.append("\n"); + buf.append("minutes: "); + buf.append(getExpressionSetSummary(minutes)); + buf.append("\n"); + buf.append("hours: "); + buf.append(getExpressionSetSummary(hours)); + buf.append("\n"); + buf.append("daysOfMonth: "); + buf.append(getExpressionSetSummary(daysOfMonth)); + buf.append("\n"); + buf.append("months: "); + buf.append(getExpressionSetSummary(months)); + buf.append("\n"); + buf.append("daysOfWeek: "); + buf.append(getExpressionSetSummary(daysOfWeek)); + buf.append("\n"); + buf.append("lastdayOfWeek: "); + buf.append(lastdayOfWeek); + buf.append("\n"); + buf.append("nearestWeekday: "); + buf.append(nearestWeekday); + buf.append("\n"); + buf.append("NthDayOfWeek: "); + buf.append(nthdayOfWeek); + buf.append("\n"); + buf.append("lastdayOfMonth: "); + buf.append(lastdayOfMonth); + buf.append("\n"); + buf.append("years: "); + buf.append(getExpressionSetSummary(years)); + buf.append("\n"); + + return buf.toString(); + } + + protected String getExpressionSetSummary(java.util.Set set) { + + if (set.contains(NO_SPEC)) { + return "?"; + } + if (set.contains(ALL_SPEC)) { + return "*"; + } + + StringBuilder buf = new StringBuilder(); + + Iterator itr = set.iterator(); + boolean first = true; + while (itr.hasNext()) { + Integer iVal = itr.next(); + String val = iVal.toString(); + if (!first) { + buf.append(","); + } + buf.append(val); + first = false; + } + + return buf.toString(); + } + + protected String getExpressionSetSummary(java.util.ArrayList list) { + + if (list.contains(NO_SPEC)) { + return "?"; + } + if (list.contains(ALL_SPEC)) { + return "*"; + } + + StringBuilder buf = new StringBuilder(); + + Iterator itr = list.iterator(); + boolean first = true; + while (itr.hasNext()) { + Integer iVal = itr.next(); + String val = iVal.toString(); + if (!first) { + buf.append(","); + } + buf.append(val); + first = false; + } + + return buf.toString(); + } + + protected int skipWhiteSpace(int i, String s) { + for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) { + } + + return i; + } + + protected int findNextWhiteSpace(int i, String s) { + for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) { + } + + return i; + } + + protected void addToSet(int val, int end, int incr, int type) + throws ParseException { + + TreeSet set = getSet(type); + + if (type == SECOND || type == MINUTE) { + if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Minute and Second values must be between 0 and 59", + -1); + } + } else if (type == HOUR) { + if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Hour values must be between 0 and 23", -1); + } + } else if (type == DAY_OF_MONTH) { + if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day of month values must be between 1 and 31", -1); + } + } else if (type == MONTH) { + if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) { + throw new ParseException( + "Month values must be between 1 and 12", -1); + } + } else if (type == DAY_OF_WEEK) { + if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT) + && (val != NO_SPEC_INT)) { + throw new ParseException( + "Day-of-Week values must be between 1 and 7", -1); + } + } + + if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) { + if (val != -1) { + set.add(val); + } else { + set.add(NO_SPEC); + } + + return; + } + + int startAt = val; + int stopAt = end; + + if (val == ALL_SPEC_INT && incr <= 0) { + incr = 1; + set.add(ALL_SPEC); // put in a marker, but also fill values + } + + if (type == SECOND || type == MINUTE) { + if (stopAt == -1) { + stopAt = 59; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } + } else if (type == HOUR) { + if (stopAt == -1) { + stopAt = 23; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 0; + } + } else if (type == DAY_OF_MONTH) { + if (stopAt == -1) { + stopAt = 31; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == MONTH) { + if (stopAt == -1) { + stopAt = 12; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == DAY_OF_WEEK) { + if (stopAt == -1) { + stopAt = 7; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1; + } + } else if (type == YEAR) { + if (stopAt == -1) { + stopAt = MAX_YEAR; + } + if (startAt == -1 || startAt == ALL_SPEC_INT) { + startAt = 1970; + } + } + + // if the end of the range is before the start, then we need to overflow into + // the next day, month etc. This is done by adding the maximum amount for that + // type, and using modulus max to determine the value being added. + int max = -1; + if (stopAt < startAt) { + switch (type) { + case SECOND: + max = 60; + break; + case MINUTE: + max = 60; + break; + case HOUR: + max = 24; + break; + case MONTH: + max = 12; + break; + case DAY_OF_WEEK: + max = 7; + break; + case DAY_OF_MONTH: + max = 31; + break; + case YEAR: + throw new IllegalArgumentException("Start year must be less than stop year"); + default: + throw new IllegalArgumentException("Unexpected type encountered"); + } + stopAt += max; + } + + for (int i = startAt; i <= stopAt; i += incr) { + if (max == -1) { + // ie: there's no max to overflow over + set.add(i); + } else { + // take the modulus to get the real value + int i2 = i % max; + + // 1-indexed ranges should not include 0, and should include their max + if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH)) { + i2 = max; + } + + set.add(i2); + } + } + } + + TreeSet getSet(int type) { + switch (type) { + case SECOND: + return seconds; + case MINUTE: + return minutes; + case HOUR: + return hours; + case DAY_OF_MONTH: + return daysOfMonth; + case MONTH: + return months; + case DAY_OF_WEEK: + return daysOfWeek; + case YEAR: + return years; + default: + return null; + } + } + + protected ValueSet getValue(int v, String s, int i) { + char c = s.charAt(i); + StringBuilder s1 = new StringBuilder(String.valueOf(v)); + while (c >= '0' && c <= '9') { + s1.append(c); + i++; + if (i >= s.length()) { + break; + } + c = s.charAt(i); + } + ValueSet val = new ValueSet(); + + val.pos = (i < s.length()) ? i : i + 1; + val.value = Integer.parseInt(s1.toString()); + return val; + } + + protected int getNumericValue(String s, int i) { + int endOfVal = findNextWhiteSpace(i, s); + String val = s.substring(i, endOfVal); + return Integer.parseInt(val); + } + + protected int getMonthNumber(String s) { + Integer integer = monthMap.get(s); + + if (integer == null) { + return -1; + } + + return integer; + } + + protected int getDayOfWeekNumber(String s) { + Integer integer = dayMap.get(s); + + if (integer == null) { + return -1; + } + + return integer; + } + + //////////////////////////////////////////////////////////////////////////// + // + // Computation Functions + // + //////////////////////////////////////////////////////////////////////////// + + public Date getTimeAfter(Date afterTime) { + + // Computation is based on Gregorian year only. + Calendar cl = new java.util.GregorianCalendar(getTimeZone()); + + // move ahead one second, since we're computing the time *after* the + // given time + afterTime = new Date(afterTime.getTime() + 1000); + // CronTrigger does not deal with milliseconds + cl.setTime(afterTime); + cl.set(Calendar.MILLISECOND, 0); + + boolean gotOne = false; + // loop until we've computed the next time, or we've past the endTime + while (!gotOne) { + + //if (endTime != null && cl.getTime().after(endTime)) return null; + if (cl.get(Calendar.YEAR) > 2999) { // prevent endless loop... + return null; + } + + SortedSet st = null; + int t = 0; + + int sec = cl.get(Calendar.SECOND); + int min = cl.get(Calendar.MINUTE); + + // get second................................................. + st = seconds.tailSet(sec); + if (st != null && st.size() != 0) { + sec = st.first(); + } else { + sec = seconds.first(); + min++; + cl.set(Calendar.MINUTE, min); + } + cl.set(Calendar.SECOND, sec); + + min = cl.get(Calendar.MINUTE); + int hr = cl.get(Calendar.HOUR_OF_DAY); + t = -1; + + // get minute................................................. + st = minutes.tailSet(min); + if (st != null && st.size() != 0) { + t = min; + min = st.first(); + } else { + min = minutes.first(); + hr++; + } + if (min != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, min); + setCalendarHour(cl, hr); + continue; + } + cl.set(Calendar.MINUTE, min); + + hr = cl.get(Calendar.HOUR_OF_DAY); + int day = cl.get(Calendar.DAY_OF_MONTH); + t = -1; + + // get hour................................................... + st = hours.tailSet(hr); + if (st != null && st.size() != 0) { + t = hr; + hr = st.first(); + } else { + hr = hours.first(); + day++; + } + if (hr != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + setCalendarHour(cl, hr); + continue; + } + cl.set(Calendar.HOUR_OF_DAY, hr); + + day = cl.get(Calendar.DAY_OF_MONTH); + int mon = cl.get(Calendar.MONTH) + 1; + // '+ 1' because calendar is 0-based for this field, and we are + // 1-based + t = -1; + int tmon = mon; + + // get day................................................... + boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC); + boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC); + if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule + st = daysOfMonth.tailSet(day); + if (lastdayOfMonth) { + if (!nearestWeekday) { + t = day; + day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + day -= lastdayOffset; + if (t > day) { + mon++; + if (mon > 12) { + mon = 1; + tmon = 3333; // ensure test of mon != tmon further below fails + cl.add(Calendar.YEAR, 1); + } + day = 1; + } + } else { + t = day; + day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + day -= lastdayOffset; + + Calendar tcal = Calendar.getInstance(getTimeZone()); + tcal.set(Calendar.SECOND, 0); + tcal.set(Calendar.MINUTE, 0); + tcal.set(Calendar.HOUR_OF_DAY, 0); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); + + int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + int dow = tcal.get(Calendar.DAY_OF_WEEK); + + if (dow == Calendar.SATURDAY && day == 1) { + day += 2; + } else if (dow == Calendar.SATURDAY) { + day -= 1; + } else if (dow == Calendar.SUNDAY && day == ldom) { + day -= 2; + } else if (dow == Calendar.SUNDAY) { + day += 1; + } + + tcal.set(Calendar.SECOND, sec); + tcal.set(Calendar.MINUTE, min); + tcal.set(Calendar.HOUR_OF_DAY, hr); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + Date nTime = tcal.getTime(); + if (nTime.before(afterTime)) { + day = 1; + mon++; + } + } + } else if (nearestWeekday) { + t = day; + day = daysOfMonth.first(); + + Calendar tcal = Calendar.getInstance(getTimeZone()); + tcal.set(Calendar.SECOND, 0); + tcal.set(Calendar.MINUTE, 0); + tcal.set(Calendar.HOUR_OF_DAY, 0); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR)); + + int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + int dow = tcal.get(Calendar.DAY_OF_WEEK); + + if (dow == Calendar.SATURDAY && day == 1) { + day += 2; + } else if (dow == Calendar.SATURDAY) { + day -= 1; + } else if (dow == Calendar.SUNDAY && day == ldom) { + day -= 2; + } else if (dow == Calendar.SUNDAY) { + day += 1; + } + + + tcal.set(Calendar.SECOND, sec); + tcal.set(Calendar.MINUTE, min); + tcal.set(Calendar.HOUR_OF_DAY, hr); + tcal.set(Calendar.DAY_OF_MONTH, day); + tcal.set(Calendar.MONTH, mon - 1); + Date nTime = tcal.getTime(); + if (nTime.before(afterTime)) { + day = daysOfMonth.first(); + mon++; + } + } else if (st != null && st.size() != 0) { + t = day; + day = st.first(); + // make sure we don't over-run a short month, such as february + int lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + if (day > lastDay) { + day = daysOfMonth.first(); + mon++; + } + } else { + day = daysOfMonth.first(); + mon++; + } + + if (day != t || mon != tmon) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we + // are 1-based + continue; + } + } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule + if (lastdayOfWeek) { // are we looking for the last XXX day of + // the month? + int dow = daysOfWeek.first(); // desired + // d-o-w + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + + if (day + daysToAdd > lDay) { // did we already miss the + // last one? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } + + // find date of last occurrence of this day in this month... + while ((day + daysToAdd + 7) <= lDay) { + daysToAdd += 7; + } + + day += daysToAdd; + + if (daysToAdd > 0) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' here because we are not promoting the month + continue; + } + + } else if (nthdayOfWeek != 0) { + // are we looking for the Nth XXX day in the month? + int dow = daysOfWeek.first(); // desired + // d-o-w + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } else if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + boolean dayShifted = false; + if (daysToAdd > 0) { + dayShifted = true; + } + + day += daysToAdd; + int weekOfMonth = day / 7; + if (day % 7 > 0) { + weekOfMonth++; + } + + daysToAdd = (nthdayOfWeek - weekOfMonth) * 7; + day += daysToAdd; + if (daysToAdd < 0 + || day > getLastDayOfMonth(mon, cl + .get(Calendar.YEAR))) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } else if (daysToAdd > 0 || dayShifted) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' here because we are NOT promoting the month + continue; + } + } else { + int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w + int dow = daysOfWeek.first(); // desired + // d-o-w + st = daysOfWeek.tailSet(cDow); + if (st != null && st.size() > 0) { + dow = st.first(); + } + + int daysToAdd = 0; + if (cDow < dow) { + daysToAdd = dow - cDow; + } + if (cDow > dow) { + daysToAdd = dow + (7 - cDow); + } + + int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR)); + + if (day + daysToAdd > lDay) { // will we pass the end of + // the month? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon); + // no '- 1' here because we are promoting the month + continue; + } else if (daysToAdd > 0) { // are we swithing days? + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, + // and we are 1-based + continue; + } + } + } else { // dayOfWSpec && !dayOfMSpec + throw new UnsupportedOperationException( + "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented."); + } + cl.set(Calendar.DAY_OF_MONTH, day); + + mon = cl.get(Calendar.MONTH) + 1; + // '+ 1' because calendar is 0-based for this field, and we are + // 1-based + int year = cl.get(Calendar.YEAR); + t = -1; + + // test for expressions that never generate a valid fire date, + // but keep looping... + if (year > MAX_YEAR) { + return null; + } + + // get month................................................... + st = months.tailSet(mon); + if (st != null && st.size() != 0) { + t = mon; + mon = st.first(); + } else { + mon = months.first(); + year++; + } + if (mon != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + cl.set(Calendar.YEAR, year); + continue; + } + cl.set(Calendar.MONTH, mon - 1); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + + year = cl.get(Calendar.YEAR); + t = -1; + + // get year................................................... + st = years.tailSet(year); + if (st != null && st.size() != 0) { + t = year; + year = st.first(); + } else { + return null; // ran out of years... + } + + if (year != t) { + cl.set(Calendar.SECOND, 0); + cl.set(Calendar.MINUTE, 0); + cl.set(Calendar.HOUR_OF_DAY, 0); + cl.set(Calendar.DAY_OF_MONTH, 1); + cl.set(Calendar.MONTH, 0); + // '- 1' because calendar is 0-based for this field, and we are + // 1-based + cl.set(Calendar.YEAR, year); + continue; + } + cl.set(Calendar.YEAR, year); + + gotOne = true; + } // while( !done ) + + return cl.getTime(); + } + + /** + * Advance the calendar to the particular hour paying particular attention + * to daylight saving problems. + * + * @param cal the calendar to operate on + * @param hour the hour to set + */ + protected void setCalendarHour(Calendar cal, int hour) { + cal.set(Calendar.HOUR_OF_DAY, hour); + if (cal.get(Calendar.HOUR_OF_DAY) != hour && hour != 24) { + cal.set(Calendar.HOUR_OF_DAY, hour + 1); + } + } + + /** + * NOT YET IMPLEMENTED: Returns the time before the given time + * that the CronExpression matches. + */ + public Date getTimeBefore(Date endTime) { + // FUTURE_TODO: implement QUARTZ-423 + return null; + } + + /** + * NOT YET IMPLEMENTED: Returns the final time that the + * CronExpression will match. + */ + public Date getFinalFireTime() { + // FUTURE_TODO: implement QUARTZ-423 + return null; + } + + protected boolean isLeapYear(int year) { + return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)); + } + + protected int getLastDayOfMonth(int monthNum, int year) { + + switch (monthNum) { + case 1: + return 31; + case 2: + return (isLeapYear(year)) ? 29 : 28; + case 3: + return 31; + case 4: + return 30; + case 5: + return 31; + case 6: + return 30; + case 7: + return 31; + case 8: + return 31; + case 9: + return 30; + case 10: + return 31; + case 11: + return 30; + case 12: + return 31; + default: + throw new IllegalArgumentException("Illegal month number: " + + monthNum); + } + } + + + private void readObject(java.io.ObjectInputStream stream) + throws java.io.IOException, ClassNotFoundException { + + stream.defaultReadObject(); + try { + buildExpression(cronExpression); + } catch (Exception ignore) { + } // never happens + } + + @Override + @Deprecated + public Object clone() { + return new CronExpression(this); + } +} + +class ValueSet { + public int value; + + public int pos; +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java new file mode 100644 index 0000000..4424277 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java @@ -0,0 +1,15 @@ +package com.xxl.job.admin.core.exception; + +/** + * @author xuxueli 2019-05-04 23:19:29 + */ +public class XxlJobException extends RuntimeException { + + public XxlJobException() { + } + + public XxlJobException(String message) { + super(message); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java new file mode 100644 index 0000000..3a9952a --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java @@ -0,0 +1,78 @@ +package com.xxl.job.admin.core.model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +/** + * Created by xuxueli on 16/9/30. + */ +public class XxlJobGroup { + + private int id; + private String appname; + private String title; + private int addressType; // 执行器地址类型:0=自动注册、1=手动录入 + private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入) + private Date updateTime; + + // registry list + private List registryList; // 执行器地址列表(系统注册) + + public List getRegistryList() { + if (addressList != null && addressList.trim().length() > 0) { + registryList = new ArrayList(Arrays.asList(addressList.split(","))); + } + return registryList; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getAppname() { + return appname; + } + + public void setAppname(String appname) { + this.appname = appname; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public int getAddressType() { + return addressType; + } + + public void setAddressType(int addressType) { + this.addressType = addressType; + } + + public String getAddressList() { + return addressList; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public void setAddressList(String addressList) { + this.addressList = addressList; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java new file mode 100644 index 0000000..ee4b02c --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java @@ -0,0 +1,237 @@ +package com.xxl.job.admin.core.model; + +import java.util.Date; + +/** + * xxl-job info + * + * @author xuxueli 2016-1-12 18:25:49 + */ +public class XxlJobInfo { + + private int id; // 主键ID + + private int jobGroup; // 执行器主键ID + private String jobDesc; + + private Date addTime; + private Date updateTime; + + private String author; // 负责人 + private String alarmEmail; // 报警邮件 + + private String scheduleType; // 调度类型 + private String scheduleConf; // 调度配置,值含义取决于调度类型 + private String misfireStrategy; // 调度过期策略 + + private String executorRouteStrategy; // 执行器路由策略 + private String executorHandler; // 执行器,任务Handler名称 + private String executorParam; // 执行器,任务参数 + private String executorBlockStrategy; // 阻塞处理策略 + private int executorTimeout; // 任务执行超时时间,单位秒 + private int executorFailRetryCount; // 失败重试次数 + + private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum + private String glueSource; // GLUE源代码 + private String glueRemark; // GLUE备注 + private Date glueUpdatetime; // GLUE更新时间 + + private String childJobId; // 子任务ID,多个逗号分隔 + + private int triggerStatus; // 调度状态:0-停止,1-运行 + private long triggerLastTime; // 上次调度时间 + private long triggerNextTime; // 下次调度时间 + + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getJobGroup() { + return jobGroup; + } + + public void setJobGroup(int jobGroup) { + this.jobGroup = jobGroup; + } + + public String getJobDesc() { + return jobDesc; + } + + public void setJobDesc(String jobDesc) { + this.jobDesc = jobDesc; + } + + public Date getAddTime() { + return addTime; + } + + public void setAddTime(Date addTime) { + this.addTime = addTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public String getScheduleType() { + return scheduleType; + } + + public void setScheduleType(String scheduleType) { + this.scheduleType = scheduleType; + } + + public String getScheduleConf() { + return scheduleConf; + } + + public void setScheduleConf(String scheduleConf) { + this.scheduleConf = scheduleConf; + } + + public String getMisfireStrategy() { + return misfireStrategy; + } + + public void setMisfireStrategy(String misfireStrategy) { + this.misfireStrategy = misfireStrategy; + } + + public String getExecutorRouteStrategy() { + return executorRouteStrategy; + } + + public void setExecutorRouteStrategy(String executorRouteStrategy) { + this.executorRouteStrategy = executorRouteStrategy; + } + + public String getExecutorHandler() { + return executorHandler; + } + + public void setExecutorHandler(String executorHandler) { + this.executorHandler = executorHandler; + } + + public String getExecutorParam() { + return executorParam; + } + + public void setExecutorParam(String executorParam) { + this.executorParam = executorParam; + } + + public String getExecutorBlockStrategy() { + return executorBlockStrategy; + } + + public void setExecutorBlockStrategy(String executorBlockStrategy) { + this.executorBlockStrategy = executorBlockStrategy; + } + + public int getExecutorTimeout() { + return executorTimeout; + } + + public void setExecutorTimeout(int executorTimeout) { + this.executorTimeout = executorTimeout; + } + + public int getExecutorFailRetryCount() { + return executorFailRetryCount; + } + + public void setExecutorFailRetryCount(int executorFailRetryCount) { + this.executorFailRetryCount = executorFailRetryCount; + } + + public String getGlueType() { + return glueType; + } + + public void setGlueType(String glueType) { + this.glueType = glueType; + } + + public String getGlueSource() { + return glueSource; + } + + public void setGlueSource(String glueSource) { + this.glueSource = glueSource; + } + + public String getGlueRemark() { + return glueRemark; + } + + public void setGlueRemark(String glueRemark) { + this.glueRemark = glueRemark; + } + + public Date getGlueUpdatetime() { + return glueUpdatetime; + } + + public void setGlueUpdatetime(Date glueUpdatetime) { + this.glueUpdatetime = glueUpdatetime; + } + + public String getChildJobId() { + return childJobId; + } + + public void setChildJobId(String childJobId) { + this.childJobId = childJobId; + } + + public int getTriggerStatus() { + return triggerStatus; + } + + public void setTriggerStatus(int triggerStatus) { + this.triggerStatus = triggerStatus; + } + + public long getTriggerLastTime() { + return triggerLastTime; + } + + public void setTriggerLastTime(long triggerLastTime) { + this.triggerLastTime = triggerLastTime; + } + + public long getTriggerNextTime() { + return triggerNextTime; + } + + public void setTriggerNextTime(long triggerNextTime) { + this.triggerNextTime = triggerNextTime; + } +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java new file mode 100644 index 0000000..f3301af --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java @@ -0,0 +1,158 @@ +package com.xxl.job.admin.core.model; + +import java.util.Date; + +/** + * xxl-job log, used to track trigger process + * + * @author xuxueli 2015-12-19 23:19:09 + */ +public class XxlJobLog { + + private long id; + + // job info + private int jobGroup; + private int jobId; + + // execute info + private String executorAddress; + private String executorHandler; + private String executorParam; + private String executorShardingParam; + private int executorFailRetryCount; + + // trigger info + private Date triggerTime; + private int triggerCode; + private String triggerMsg; + + // handle info + private Date handleTime; + private int handleCode; + private String handleMsg; + + // alarm info + private int alarmStatus; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public int getJobGroup() { + return jobGroup; + } + + public void setJobGroup(int jobGroup) { + this.jobGroup = jobGroup; + } + + public int getJobId() { + return jobId; + } + + public void setJobId(int jobId) { + this.jobId = jobId; + } + + public String getExecutorAddress() { + return executorAddress; + } + + public void setExecutorAddress(String executorAddress) { + this.executorAddress = executorAddress; + } + + public String getExecutorHandler() { + return executorHandler; + } + + public void setExecutorHandler(String executorHandler) { + this.executorHandler = executorHandler; + } + + public String getExecutorParam() { + return executorParam; + } + + public void setExecutorParam(String executorParam) { + this.executorParam = executorParam; + } + + public String getExecutorShardingParam() { + return executorShardingParam; + } + + public void setExecutorShardingParam(String executorShardingParam) { + this.executorShardingParam = executorShardingParam; + } + + public int getExecutorFailRetryCount() { + return executorFailRetryCount; + } + + public void setExecutorFailRetryCount(int executorFailRetryCount) { + this.executorFailRetryCount = executorFailRetryCount; + } + + public Date getTriggerTime() { + return triggerTime; + } + + public void setTriggerTime(Date triggerTime) { + this.triggerTime = triggerTime; + } + + public int getTriggerCode() { + return triggerCode; + } + + public void setTriggerCode(int triggerCode) { + this.triggerCode = triggerCode; + } + + public String getTriggerMsg() { + return triggerMsg; + } + + public void setTriggerMsg(String triggerMsg) { + this.triggerMsg = triggerMsg; + } + + public Date getHandleTime() { + return handleTime; + } + + public void setHandleTime(Date handleTime) { + this.handleTime = handleTime; + } + + public int getHandleCode() { + return handleCode; + } + + public void setHandleCode(int handleCode) { + this.handleCode = handleCode; + } + + public String getHandleMsg() { + return handleMsg; + } + + public void setHandleMsg(String handleMsg) { + this.handleMsg = handleMsg; + } + + public int getAlarmStatus() { + return alarmStatus; + } + + public void setAlarmStatus(int alarmStatus) { + this.alarmStatus = alarmStatus; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java new file mode 100644 index 0000000..2da3c2d --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java @@ -0,0 +1,76 @@ +package com.xxl.job.admin.core.model; + +import java.util.Date; + +/** + * xxl-job log for glue, used to track job code process + * + * @author xuxueli 2016-5-19 17:57:46 + */ +public class XxlJobLogGlue { + + private int id; + private int jobId; // 任务主键ID + private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum + private String glueSource; + private String glueRemark; + private Date addTime; + private Date updateTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getJobId() { + return jobId; + } + + public void setJobId(int jobId) { + this.jobId = jobId; + } + + public String getGlueType() { + return glueType; + } + + public void setGlueType(String glueType) { + this.glueType = glueType; + } + + public String getGlueSource() { + return glueSource; + } + + public void setGlueSource(String glueSource) { + this.glueSource = glueSource; + } + + public String getGlueRemark() { + return glueRemark; + } + + public void setGlueRemark(String glueRemark) { + this.glueRemark = glueRemark; + } + + public Date getAddTime() { + return addTime; + } + + public void setAddTime(Date addTime) { + this.addTime = addTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java new file mode 100644 index 0000000..e58ff1a --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java @@ -0,0 +1,54 @@ +package com.xxl.job.admin.core.model; + +import java.util.Date; + +public class XxlJobLogReport { + + private int id; + + private Date triggerDay; + + private int runningCount; + private int sucCount; + private int failCount; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Date getTriggerDay() { + return triggerDay; + } + + public void setTriggerDay(Date triggerDay) { + this.triggerDay = triggerDay; + } + + public int getRunningCount() { + return runningCount; + } + + public void setRunningCount(int runningCount) { + this.runningCount = runningCount; + } + + public int getSucCount() { + return sucCount; + } + + public void setSucCount(int sucCount) { + this.sucCount = sucCount; + } + + public int getFailCount() { + return failCount; + } + + public void setFailCount(int failCount) { + this.failCount = failCount; + } +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java new file mode 100644 index 0000000..924d6d3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java @@ -0,0 +1,55 @@ +package com.xxl.job.admin.core.model; + +import java.util.Date; + +/** + * Created by xuxueli on 16/9/30. + */ +public class XxlJobRegistry { + + private int id; + private String registryGroup; + private String registryKey; + private String registryValue; + private Date updateTime; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getRegistryGroup() { + return registryGroup; + } + + public void setRegistryGroup(String registryGroup) { + this.registryGroup = registryGroup; + } + + public String getRegistryKey() { + return registryKey; + } + + public void setRegistryKey(String registryKey) { + this.registryKey = registryKey; + } + + public String getRegistryValue() { + return registryValue; + } + + public void setRegistryValue(String registryValue) { + this.registryValue = registryValue; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java new file mode 100644 index 0000000..6f696df --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java @@ -0,0 +1,73 @@ +package com.xxl.job.admin.core.model; + +import org.springframework.util.StringUtils; + +/** + * @author xuxueli 2019-05-04 16:43:12 + */ +public class XxlJobUser { + + private int id; + private String username; // 账号 + private String password; // 密码 + private int role; // 角色:0-普通用户、1-管理员 + private String permission; // 权限:执行器ID列表,多个逗号分割 + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public int getRole() { + return role; + } + + public void setRole(int role) { + this.role = role; + } + + public String getPermission() { + return permission; + } + + public void setPermission(String permission) { + this.permission = permission; + } + + // plugin + public boolean validPermission(int jobGroup) { + if (this.role == 1) { + return true; + } else { + if (StringUtils.hasText(this.permission)) { + for (String permissionItem : this.permission.split(",")) { + if (String.valueOf(jobGroup).equals(permissionItem)) { + return true; + } + } + } + return false; + } + + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java new file mode 100644 index 0000000..5d1f2a0 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java @@ -0,0 +1,32 @@ +package com.xxl.job.admin.core.old;//package com.xxl.job.admin.core.jobbean; +// +//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; +//import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +//import org.quartz.JobExecutionContext; +//import org.quartz.JobExecutionException; +//import org.quartz.JobKey; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.scheduling.quartz.QuartzJobBean; +// +///** +// * http job bean +// * “@DisallowConcurrentExecution” disable concurrent, thread size can not be only one, better given more +// * @author xuxueli 2015-12-17 18:20:34 +// */ +////@DisallowConcurrentExecution +//public class RemoteHttpJobBean extends QuartzJobBean { +// private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class); +// +// @Override +// protected void executeInternal(JobExecutionContext context) +// throws JobExecutionException { +// +// // load jobId +// JobKey jobKey = context.getTrigger().getJobKey(); +// Integer jobId = Integer.valueOf(jobKey.getName()); +// +// +// } +// +//} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java new file mode 100644 index 0000000..5ae81bd --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java @@ -0,0 +1,413 @@ +package com.xxl.job.admin.core.old;//package com.xxl.job.admin.core.schedule; +// +//import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +//import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean; +//import com.xxl.job.admin.core.model.XxlJobInfo; +//import com.xxl.job.admin.core.thread.JobFailMonitorHelper; +//import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper; +//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper; +//import com.xxl.job.admin.core.util.I18nUtil; +//import com.xxl.job.core.biz.AdminBiz; +//import com.xxl.job.core.biz.ExecutorBiz; +//import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +//import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory; +//import com.xxl.rpc.remoting.invoker.call.CallType; +//import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean; +//import com.xxl.rpc.remoting.invoker.route.LoadBalance; +//import com.xxl.rpc.remoting.net.NetEnum; +//import com.xxl.rpc.remoting.net.impl.servlet.server.ServletServerHandler; +//import com.xxl.rpc.remoting.provider.XxlRpcProviderFactory; +//import com.xxl.rpc.serialize.Serializer; +//import org.quartz.*; +//import org.quartz.Trigger.TriggerState; +//import org.quartz.impl.triggers.CronTriggerImpl; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.util.Assert; +// +//import javax.servlet.ServletException; +//import javax.servlet.http.HttpServletRequest; +//import javax.servlet.http.HttpServletResponse; +//import java.io.IOException; +//import java.util.Date; +//import java.util.concurrent.ConcurrentHashMap; +// +///** +// * base quartz scheduler util +// * @author xuxueli 2015-12-19 16:13:53 +// */ +//public final class XxlJobDynamicScheduler { +// private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler_old.class); +// +// // ---------------------- param ---------------------- +// +// // scheduler +// private static Scheduler scheduler; +// public void setScheduler(Scheduler scheduler) { +// XxlJobDynamicScheduler_old.scheduler = scheduler; +// } +// +// +// // ---------------------- init + destroy ---------------------- +// public void start() throws Exception { +// // valid +// Assert.notNull(scheduler, "quartz scheduler is null"); +// +// // init i18n +// initI18n(); +// +// // admin registry monitor run +// JobRegistryMonitorHelper.getInstance().start(); +// +// // admin monitor run +// JobFailMonitorHelper.getInstance().start(); +// +// // admin-server +// initRpcProvider(); +// +// logger.info(">>>>>>>>> init xxl-job admin success."); +// } +// +// +// public void destroy() throws Exception { +// // admin trigger pool stop +// JobTriggerPoolHelper.toStop(); +// +// // admin registry stop +// JobRegistryMonitorHelper.getInstance().toStop(); +// +// // admin monitor stop +// JobFailMonitorHelper.getInstance().toStop(); +// +// // admin-server +// stopRpcProvider(); +// } +// +// +// // ---------------------- I18n ---------------------- +// +// private void initI18n(){ +// for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) { +// item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name()))); +// } +// } +// +// +// // ---------------------- admin rpc provider (no server version) ---------------------- +// private static ServletServerHandler servletServerHandler; +// private void initRpcProvider(){ +// // init +// XxlRpcProviderFactory xxlRpcProviderFactory = new XxlRpcProviderFactory(); +// xxlRpcProviderFactory.initConfig( +// NetEnum.NETTY_HTTP, +// Serializer.SerializeEnum.HESSIAN.getSerializer(), +// null, +// 0, +// XxlJobAdminConfig.getAdminConfig().getAccessToken(), +// null, +// null); +// +// // add services +// xxlRpcProviderFactory.addService(AdminBiz.class.getName(), null, XxlJobAdminConfig.getAdminConfig().getAdminBiz()); +// +// // servlet handler +// servletServerHandler = new ServletServerHandler(xxlRpcProviderFactory); +// } +// private void stopRpcProvider() throws Exception { +// XxlRpcInvokerFactory.getInstance().stop(); +// } +// public static void invokeAdminService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { +// servletServerHandler.handle(null, request, response); +// } +// +// +// // ---------------------- executor-client ---------------------- +// private static ConcurrentHashMap executorBizRepository = new ConcurrentHashMap(); +// public static ExecutorBiz getExecutorBiz(String address) throws Exception { +// // valid +// if (address==null || address.trim().length()==0) { +// return null; +// } +// +// // load-cache +// address = address.trim(); +// ExecutorBiz executorBiz = executorBizRepository.get(address); +// if (executorBiz != null) { +// return executorBiz; +// } +// +// // set-cache +// executorBiz = (ExecutorBiz) new XxlRpcReferenceBean( +// NetEnum.NETTY_HTTP, +// Serializer.SerializeEnum.HESSIAN.getSerializer(), +// CallType.SYNC, +// LoadBalance.ROUND, +// ExecutorBiz.class, +// null, +// 5000, +// address, +// XxlJobAdminConfig.getAdminConfig().getAccessToken(), +// null, +// null).getObject(); +// +// executorBizRepository.put(address, executorBiz); +// return executorBiz; +// } +// +// +// // ---------------------- schedule util ---------------------- +// +// /** +// * fill job info +// * +// * @param jobInfo +// */ +// public static void fillJobInfo(XxlJobInfo jobInfo) { +// +// String name = String.valueOf(jobInfo.getId()); +// +// // trigger key +// TriggerKey triggerKey = TriggerKey.triggerKey(name); +// try { +// +// // trigger cron +// Trigger trigger = scheduler.getTrigger(triggerKey); +// if (trigger!=null && trigger instanceof CronTriggerImpl) { +// String cronExpression = ((CronTriggerImpl) trigger).getCronExpression(); +// jobInfo.setJobCron(cronExpression); +// } +// +// // trigger state +// TriggerState triggerState = scheduler.getTriggerState(triggerKey); +// if (triggerState!=null) { +// jobInfo.setJobStatus(triggerState.name()); +// } +// +// //JobKey jobKey = new JobKey(jobInfo.getJobName(), String.valueOf(jobInfo.getJobGroup())); +// //JobDetail jobDetail = scheduler.getJobDetail(jobKey); +// //String jobClass = jobDetail.getJobClass().getName(); +// +// } catch (SchedulerException e) { +// logger.error(e.getMessage(), e); +// } +// } +// +// +// /** +// * add trigger + job +// * +// * @param jobName +// * @param cronExpression +// * @return +// * @throws SchedulerException +// */ +// public static boolean addJob(String jobName, String cronExpression) throws SchedulerException { +// // 1、job key +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// JobKey jobKey = new JobKey(jobName); +// +// // 2、valid +// if (scheduler.checkExists(triggerKey)) { +// return true; // PASS +// } +// +// // 3、corn trigger +// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度 +// CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); +// +// // 4、job detail +// Class jobClass_ = RemoteHttpJobBean.class; // Class.forName(jobInfo.getJobClass()); +// JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build(); +// +// /*if (jobInfo.getJobData()!=null) { +// JobDataMap jobDataMap = jobDetail.getJobDataMap(); +// jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class)); +// // JobExecutionContext context.getMergedJobDataMap().get("mailGuid"); +// }*/ +// +// // 5、schedule job +// Date date = scheduler.scheduleJob(jobDetail, cronTrigger); +// +// logger.info(">>>>>>>>>>> addJob success(quartz), jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date); +// return true; +// } +// +// +// /** +// * remove trigger + job +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// public static boolean removeJob(String jobName) throws SchedulerException { +// +// JobKey jobKey = new JobKey(jobName); +// scheduler.deleteJob(jobKey); +// +// /*TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// if (scheduler.checkExists(triggerKey)) { +// scheduler.unscheduleJob(triggerKey); // trigger + job +// }*/ +// +// logger.info(">>>>>>>>>>> removeJob success(quartz), jobKey:{}", jobKey); +// return true; +// } +// +// +// /** +// * updateJobCron +// * +// * @param jobName +// * @param cronExpression +// * @return +// * @throws SchedulerException +// */ +// public static boolean updateJobCron(String jobName, String cronExpression) throws SchedulerException { +// +// // 1、job key +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// // 2、valid +// if (!scheduler.checkExists(triggerKey)) { +// return true; // PASS +// } +// +// CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); +// +// // 3、avoid repeat cron +// String oldCron = oldTrigger.getCronExpression(); +// if (oldCron.equals(cronExpression)){ +// return true; // PASS +// } +// +// // 4、new cron trigger +// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); +// oldTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build(); +// +// // 5、rescheduleJob +// scheduler.rescheduleJob(triggerKey, oldTrigger); +// +// /* +// JobKey jobKey = new JobKey(jobName); +// +// // old job detail +// JobDetail jobDetail = scheduler.getJobDetail(jobKey); +// +// // new trigger +// HashSet triggerSet = new HashSet(); +// triggerSet.add(cronTrigger); +// // cover trigger of job detail +// scheduler.scheduleJob(jobDetail, triggerSet, true);*/ +// +// logger.info(">>>>>>>>>>> resumeJob success, JobName:{}", jobName); +// return true; +// } +// +// +// /** +// * pause +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// /*public static boolean pauseJob(String jobName) throws SchedulerException { +// +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// boolean result = false; +// if (scheduler.checkExists(triggerKey)) { +// scheduler.pauseTrigger(triggerKey); +// result = true; +// } +// +// logger.info(">>>>>>>>>>> pauseJob {}, triggerKey:{}", (result?"success":"fail"),triggerKey); +// return result; +// }*/ +// +// +// /** +// * resume +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// /*public static boolean resumeJob(String jobName) throws SchedulerException { +// +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// boolean result = false; +// if (scheduler.checkExists(triggerKey)) { +// scheduler.resumeTrigger(triggerKey); +// result = true; +// } +// +// logger.info(">>>>>>>>>>> resumeJob {}, triggerKey:{}", (result?"success":"fail"), triggerKey); +// return result; +// }*/ +// +// +// /** +// * run +// * +// * @param jobName +// * @return +// * @throws SchedulerException +// */ +// /*public static boolean triggerJob(String jobName) throws SchedulerException { +// // TriggerKey : name + group +// JobKey jobKey = new JobKey(jobName); +// TriggerKey triggerKey = TriggerKey.triggerKey(jobName); +// +// boolean result = false; +// if (scheduler.checkExists(triggerKey)) { +// scheduler.triggerJob(jobKey); +// result = true; +// logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey); +// } else { +// logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey); +// } +// return result; +// }*/ +// +// +// /** +// * finaAllJobList +// * +// * @return +// *//* +// @Deprecated +// public static List> finaAllJobList(){ +// List> jobList = new ArrayList>(); +// +// try { +// if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) { +// return null; +// } +// String groupName = scheduler.getJobGroupNames().get(0); +// Set jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName)); +// if (jobKeys!=null && jobKeys.size()>0) { +// for (JobKey jobKey : jobKeys) { +// TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP); +// Trigger trigger = scheduler.getTrigger(triggerKey); +// JobDetail jobDetail = scheduler.getJobDetail(jobKey); +// TriggerState triggerState = scheduler.getTriggerState(triggerKey); +// Map jobMap = new HashMap(); +// jobMap.put("TriggerKey", triggerKey); +// jobMap.put("Trigger", trigger); +// jobMap.put("JobDetail", jobDetail); +// jobMap.put("TriggerState", triggerState); +// jobList.add(jobMap); +// } +// } +// +// } catch (SchedulerException e) { +// logger.error(e.getMessage(), e); +// return null; +// } +// return jobList; +// }*/ +// +//} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java new file mode 100644 index 0000000..74f3f9d --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java @@ -0,0 +1,58 @@ +package com.xxl.job.admin.core.old;//package com.xxl.job.admin.core.quartz; +// +//import org.quartz.SchedulerConfigException; +//import org.quartz.spi.ThreadPool; +// +///** +// * single thread pool, for async trigger +// * +// * @author xuxueli 2019-03-06 +// */ +//public class XxlJobThreadPool implements ThreadPool { +// +// @Override +// public boolean runInThread(Runnable runnable) { +// +// // async run +// runnable.run(); +// return true; +// +// //return false; +// } +// +// @Override +// public int blockForAvailableThreads() { +// return 1; +// } +// +// @Override +// public void initialize() throws SchedulerConfigException { +// +// } +// +// @Override +// public void shutdown(boolean waitForJobsToComplete) { +// +// } +// +// @Override +// public int getPoolSize() { +// return 1; +// } +// +// @Override +// public void setInstanceId(String schedInstId) { +// +// } +// +// @Override +// public void setInstanceName(String schedName) { +// +// } +// +// // support +// public void setThreadCount(int count) { +// // +// } +// +//} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java new file mode 100644 index 0000000..1903b93 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java @@ -0,0 +1,49 @@ +package com.xxl.job.admin.core.route; + +import com.xxl.job.admin.core.route.strategy.*; +import com.xxl.job.admin.core.util.I18nUtil; + +/** + * Created by xuxueli on 17/3/10. + */ +public enum ExecutorRouteStrategyEnum { + + FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()), + LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()), + ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()), + RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()), + CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()), + LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()), + LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()), + FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()), + BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()), + SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null); + + ExecutorRouteStrategyEnum(String title, ExecutorRouter router) { + this.title = title; + this.router = router; + } + + private String title; + private ExecutorRouter router; + + public String getTitle() { + return title; + } + + public ExecutorRouter getRouter() { + return router; + } + + public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem) { + if (name != null) { + for (ExecutorRouteStrategyEnum item : ExecutorRouteStrategyEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + } + return defaultItem; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java new file mode 100644 index 0000000..7ca0d46 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java @@ -0,0 +1,24 @@ +package com.xxl.job.admin.core.route; + +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public abstract class ExecutorRouter { + protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class); + + /** + * route address + * + * @param addressList + * @return ReturnT.content=address + */ + public abstract ReturnT route(TriggerParam triggerParam, List addressList); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java new file mode 100644 index 0000000..a36fb4c --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java @@ -0,0 +1,48 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.scheduler.XxlJobScheduler; +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.model.IdleBeatParam; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteBusyover extends ExecutorRouter { + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + StringBuffer idleBeatResultSB = new StringBuffer(); + for (String address : addressList) { + // beat + ReturnT idleBeatResult = null; + try { + ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address); + idleBeatResult = executorBiz.idleBeat(new IdleBeatParam(triggerParam.getJobId())); + } catch (Exception e) { + logger.error(e.getMessage(), e); + idleBeatResult = new ReturnT(ReturnT.FAIL_CODE, "" + e); + } + idleBeatResultSB.append((idleBeatResultSB.length() > 0) ? "

" : "") + .append(I18nUtil.getString("jobconf_idleBeat") + ":") + .append("
address:").append(address) + .append("
code:").append(idleBeatResult.getCode()) + .append("
msg:").append(idleBeatResult.getMsg()); + + // beat success + if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) { + idleBeatResult.setMsg(idleBeatResultSB.toString()); + idleBeatResult.setContent(address); + return idleBeatResult; + } + } + + return new ReturnT(ReturnT.FAIL_CODE, idleBeatResultSB.toString()); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java new file mode 100644 index 0000000..abd4724 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java @@ -0,0 +1,86 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * 分组下机器地址相同,不同JOB均匀散列在不同机器上,保证分组下机器分配JOB平均;且每个JOB固定调度其中一台机器; + * a、virtual node:解决不均衡问题 + * b、hash method replace hashCode:String的hashCode可能重复,需要进一步扩大hashCode的取值范围 + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteConsistentHash extends ExecutorRouter { + + private static int VIRTUAL_NODE_NUM = 100; + + /** + * get hash code on 2^32 ring (md5散列的方式计算hash值) + * + * @param key + * @return + */ + private static long hash(String key) { + + // md5 byte + MessageDigest md5; + try { + md5 = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("MD5 not supported", e); + } + md5.reset(); + byte[] keyBytes = null; + try { + keyBytes = key.getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException("Unknown string :" + key, e); + } + + md5.update(keyBytes); + byte[] digest = md5.digest(); + + // hash code, Truncate to 32-bits + long hashCode = ((long) (digest[3] & 0xFF) << 24) + | ((long) (digest[2] & 0xFF) << 16) + | ((long) (digest[1] & 0xFF) << 8) + | (digest[0] & 0xFF); + + long truncateHashCode = hashCode & 0xffffffffL; + return truncateHashCode; + } + + public String hashJob(int jobId, List addressList) { + + // ------A1------A2-------A3------ + // -----------J1------------------ + TreeMap addressRing = new TreeMap(); + for (String address : addressList) { + for (int i = 0; i < VIRTUAL_NODE_NUM; i++) { + long addressHash = hash("SHARD-" + address + "-NODE-" + i); + addressRing.put(addressHash, address); + } + } + + long jobHash = hash(String.valueOf(jobId)); + SortedMap lastRing = addressRing.tailMap(jobHash); + if (!lastRing.isEmpty()) { + return lastRing.get(lastRing.firstKey()); + } + return addressRing.firstEntry().getValue(); + } + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + String address = hashJob(triggerParam.getJobId(), addressList); + return new ReturnT(address); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java new file mode 100644 index 0000000..a889fad --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java @@ -0,0 +1,48 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.scheduler.XxlJobScheduler; +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteFailover extends ExecutorRouter { + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + + StringBuffer beatResultSB = new StringBuffer(); + for (String address : addressList) { + // beat + ReturnT beatResult = null; + try { + ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address); + beatResult = executorBiz.beat(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + beatResult = new ReturnT(ReturnT.FAIL_CODE, "" + e); + } + beatResultSB.append((beatResultSB.length() > 0) ? "

" : "") + .append(I18nUtil.getString("jobconf_beat") + ":") + .append("
address:").append(address) + .append("
code:").append(beatResult.getCode()) + .append("
msg:").append(beatResult.getMsg()); + + // beat success + if (beatResult.getCode() == ReturnT.SUCCESS_CODE) { + + beatResult.setMsg(beatResultSB.toString()); + beatResult.setContent(address); + return beatResult; + } + } + return new ReturnT(ReturnT.FAIL_CODE, beatResultSB.toString()); + + } +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java new file mode 100644 index 0000000..a0fe0c7 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java @@ -0,0 +1,19 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteFirst extends ExecutorRouter { + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + return new ReturnT(addressList.get(0)); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java new file mode 100644 index 0000000..5eadf98 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java @@ -0,0 +1,79 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 单个JOB对应的每个执行器,使用频率最低的优先被选举 + * a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数 + * b、LRU(Least Recently Used):最近最久未使用,时间 + *

+ * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteLFU extends ExecutorRouter { + + private static ConcurrentMap> jobLfuMap = new ConcurrentHashMap>(); + private static long CACHE_VALID_TIME = 0; + + public String route(int jobId, List addressList) { + + // cache clear + if (System.currentTimeMillis() > CACHE_VALID_TIME) { + jobLfuMap.clear(); + CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; + } + + // lfu item init + HashMap lfuItemMap = jobLfuMap.get(jobId); // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList; + if (lfuItemMap == null) { + lfuItemMap = new HashMap(); + jobLfuMap.putIfAbsent(jobId, lfuItemMap); // 避免重复覆盖 + } + + // put new + for (String address : addressList) { + if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) > 1000000) { + lfuItemMap.put(address, new Random().nextInt(addressList.size())); // 初始化时主动Random一次,缓解首次压力 + } + } + // remove old + List delKeys = new ArrayList<>(); + for (String existKey : lfuItemMap.keySet()) { + if (!addressList.contains(existKey)) { + delKeys.add(existKey); + } + } + if (delKeys.size() > 0) { + for (String delKey : delKeys) { + lfuItemMap.remove(delKey); + } + } + + // load least userd count address + List> lfuItemList = new ArrayList>(lfuItemMap.entrySet()); + Collections.sort(lfuItemList, new Comparator>() { + @Override + public int compare(Map.Entry o1, Map.Entry o2) { + return o1.getValue().compareTo(o2.getValue()); + } + }); + + Map.Entry addressItem = lfuItemList.get(0); + String minAddress = addressItem.getKey(); + addressItem.setValue(addressItem.getValue() + 1); + + return addressItem.getKey(); + } + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + String address = route(triggerParam.getJobId(), addressList); + return new ReturnT(address); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java new file mode 100644 index 0000000..02c9424 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java @@ -0,0 +1,76 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * 单个JOB对应的每个执行器,最久为使用的优先被选举 + * a、LFU(Least Frequently Used):最不经常使用,频率/次数 + * b(*)、LRU(Least Recently Used):最近最久未使用,时间 + *

+ * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteLRU extends ExecutorRouter { + + private static ConcurrentMap> jobLRUMap = new ConcurrentHashMap>(); + private static long CACHE_VALID_TIME = 0; + + public String route(int jobId, List addressList) { + + // cache clear + if (System.currentTimeMillis() > CACHE_VALID_TIME) { + jobLRUMap.clear(); + CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; + } + + // init lru + LinkedHashMap lruItem = jobLRUMap.get(jobId); + if (lruItem == null) { + /** + * LinkedHashMap + * a、accessOrder:true=访问顺序排序(get/put时排序);false=插入顺序排期; + * b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法; + */ + lruItem = new LinkedHashMap(16, 0.75f, true); + jobLRUMap.putIfAbsent(jobId, lruItem); + } + + // put new + for (String address : addressList) { + if (!lruItem.containsKey(address)) { + lruItem.put(address, address); + } + } + // remove old + List delKeys = new ArrayList<>(); + for (String existKey : lruItem.keySet()) { + if (!addressList.contains(existKey)) { + delKeys.add(existKey); + } + } + if (delKeys.size() > 0) { + for (String delKey : delKeys) { + lruItem.remove(delKey); + } + } + + // load + String eldestKey = lruItem.entrySet().iterator().next().getKey(); + String eldestValue = lruItem.get(eldestKey); + return eldestValue; + } + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + String address = route(triggerParam.getJobId(), addressList); + return new ReturnT(address); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java new file mode 100644 index 0000000..d96059d --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java @@ -0,0 +1,19 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.List; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteLast extends ExecutorRouter { + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + return new ReturnT(addressList.get(addressList.size() - 1)); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java new file mode 100644 index 0000000..5ea4a38 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java @@ -0,0 +1,23 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.List; +import java.util.Random; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteRandom extends ExecutorRouter { + + private static Random localRandom = new Random(); + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + String address = addressList.get(localRandom.nextInt(addressList.size())); + return new ReturnT(address); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java new file mode 100644 index 0000000..dfea0ef --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java @@ -0,0 +1,46 @@ +package com.xxl.job.admin.core.route.strategy; + +import com.xxl.job.admin.core.route.ExecutorRouter; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; + +import java.util.List; +import java.util.Random; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Created by xuxueli on 17/3/10. + */ +public class ExecutorRouteRound extends ExecutorRouter { + + private static ConcurrentMap routeCountEachJob = new ConcurrentHashMap<>(); + private static long CACHE_VALID_TIME = 0; + + private static int count(int jobId) { + // cache clear + if (System.currentTimeMillis() > CACHE_VALID_TIME) { + routeCountEachJob.clear(); + CACHE_VALID_TIME = System.currentTimeMillis() + 1000 * 60 * 60 * 24; + } + + AtomicInteger count = routeCountEachJob.get(jobId); + if (count == null || count.get() > 1000000) { + // 初始化时主动Random一次,缓解首次压力 + count = new AtomicInteger(new Random().nextInt(100)); + } else { + // count++ + count.addAndGet(1); + } + routeCountEachJob.put(jobId, count); + return count.get(); + } + + @Override + public ReturnT route(TriggerParam triggerParam, List addressList) { + String address = addressList.get(count(triggerParam.getJobId()) % addressList.size()); + return new ReturnT(address); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java new file mode 100644 index 0000000..6abc5d5 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java @@ -0,0 +1,39 @@ +package com.xxl.job.admin.core.scheduler; + +import com.xxl.job.admin.core.util.I18nUtil; + +/** + * @author xuxueli 2020-10-29 21:11:23 + */ +public enum MisfireStrategyEnum { + + /** + * do nothing + */ + DO_NOTHING(I18nUtil.getString("misfire_strategy_do_nothing")), + + /** + * fire once now + */ + FIRE_ONCE_NOW(I18nUtil.getString("misfire_strategy_fire_once_now")); + + private String title; + + MisfireStrategyEnum(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public static MisfireStrategyEnum match(String name, MisfireStrategyEnum defaultItem) { + for (MisfireStrategyEnum item : MisfireStrategyEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + return defaultItem; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java new file mode 100644 index 0000000..f01d1fb --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java @@ -0,0 +1,46 @@ +package com.xxl.job.admin.core.scheduler; + +import com.xxl.job.admin.core.util.I18nUtil; + +/** + * @author xuxueli 2020-10-29 21:11:23 + */ +public enum ScheduleTypeEnum { + + NONE(I18nUtil.getString("schedule_type_none")), + + /** + * schedule by cron + */ + CRON(I18nUtil.getString("schedule_type_cron")), + + /** + * schedule by fixed rate (in seconds) + */ + FIX_RATE(I18nUtil.getString("schedule_type_fix_rate")), + + /** + * schedule by fix delay (in seconds), after the last time + */ + /*FIX_DELAY(I18nUtil.getString("schedule_type_fix_delay"))*/; + + private String title; + + ScheduleTypeEnum(String title) { + this.title = title; + } + + public String getTitle() { + return title; + } + + public static ScheduleTypeEnum match(String name, ScheduleTypeEnum defaultItem) { + for (ScheduleTypeEnum item : ScheduleTypeEnum.values()) { + if (item.name().equals(name)) { + return item; + } + } + return defaultItem; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java new file mode 100644 index 0000000..26dba69 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java @@ -0,0 +1,102 @@ +package com.xxl.job.admin.core.scheduler; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.thread.*; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.client.ExecutorBizClient; +import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * @author xuxueli 2018-10-28 00:18:17 + */ + +public class XxlJobScheduler { + private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class); + + + public void init() throws Exception { + // init i18n + initI18n(); + + // admin trigger pool start + JobTriggerPoolHelper.toStart(); + + // admin registry monitor run + JobRegistryHelper.getInstance().start(); + + // admin fail-monitor run + JobFailMonitorHelper.getInstance().start(); + + // admin lose-monitor run ( depend on JobTriggerPoolHelper ) + JobCompleteHelper.getInstance().start(); + + // admin log report start + JobLogReportHelper.getInstance().start(); + + // start-schedule ( depend on JobTriggerPoolHelper ) + JobScheduleHelper.getInstance().start(); + + logger.info(">>>>>>>>> init xxl-job admin success."); + } + + + public void destroy() throws Exception { + + // stop-schedule + JobScheduleHelper.getInstance().toStop(); + + // admin log report stop + JobLogReportHelper.getInstance().toStop(); + + // admin lose-monitor stop + JobCompleteHelper.getInstance().toStop(); + + // admin fail-monitor stop + JobFailMonitorHelper.getInstance().toStop(); + + // admin registry stop + JobRegistryHelper.getInstance().toStop(); + + // admin trigger pool stop + JobTriggerPoolHelper.toStop(); + + } + + // ---------------------- I18n ---------------------- + + private void initI18n() { + for (ExecutorBlockStrategyEnum item : ExecutorBlockStrategyEnum.values()) { + item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name()))); + } + } + + // ---------------------- executor-client ---------------------- + private static ConcurrentMap executorBizRepository = new ConcurrentHashMap(); + + public static ExecutorBiz getExecutorBiz(String address) throws Exception { + // valid + if (address == null || address.trim().length() == 0) { + return null; + } + + // load-cache + address = address.trim(); + ExecutorBiz executorBiz = executorBizRepository.get(address); + if (executorBiz != null) { + return executorBiz; + } + + // set-cache + executorBiz = new ExecutorBizClient(address, XxlJobAdminConfig.getAdminConfig().getAccessToken()); + + executorBizRepository.put(address, executorBiz); + return executorBiz; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java new file mode 100644 index 0000000..37b9bf8 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java @@ -0,0 +1,185 @@ +package com.xxl.job.admin.core.thread; + +import com.xxl.job.admin.core.complete.XxlJobCompleter; +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobLog; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.model.HandleCallbackParam; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.util.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.List; +import java.util.concurrent.*; + +/** + * job lose-monitor instance + * + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobCompleteHelper { + private static Logger logger = LoggerFactory.getLogger(JobCompleteHelper.class); + + private static JobCompleteHelper instance = new JobCompleteHelper(); + + public static JobCompleteHelper getInstance() { + return instance; + } + + // ---------------------- monitor ---------------------- + + private ThreadPoolExecutor callbackThreadPool = null; + private Thread monitorThread; + private volatile boolean toStop = false; + + public void start() { + + // for callback + callbackThreadPool = new ThreadPoolExecutor( + 2, + 20, + 30L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(3000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobLosedMonitorHelper-callbackThreadPool-" + r.hashCode()); + } + }, + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + r.run(); + logger.warn(">>>>>>>>>>> xxl-job, callback too fast, match threadpool rejected handler(run now)."); + } + }); + + + // for monitor + monitorThread = new Thread(new Runnable() { + + @Override + public void run() { + + // wait for JobTriggerPoolHelper-init + try { + TimeUnit.MILLISECONDS.sleep(50); + } catch (InterruptedException e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + // monitor + while (!toStop) { + try { + // 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min,且对应执行器心跳注册失败不在线,则将本地调度主动标记失败; + Date losedTime = DateUtil.addMinutes(new Date(), -10); + List losedJobIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLostJobIds(losedTime); + + if (losedJobIds != null && losedJobIds.size() > 0) { + for (Long logId : losedJobIds) { + + XxlJobLog jobLog = new XxlJobLog(); + jobLog.setId(logId); + + jobLog.setHandleTime(new Date()); + jobLog.setHandleCode(ReturnT.FAIL_CODE); + jobLog.setHandleMsg(I18nUtil.getString("joblog_lost_fail")); + + XxlJobCompleter.updateHandleInfoAndFinish(jobLog); + } + + } + } catch (Exception e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e); + } + } + + try { + TimeUnit.SECONDS.sleep(60); + } catch (Exception e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop"); + + } + }); + monitorThread.setDaemon(true); + monitorThread.setName("xxl-job, admin JobLosedMonitorHelper"); + monitorThread.start(); + } + + public void toStop() { + toStop = true; + + // stop registryOrRemoveThreadPool + callbackThreadPool.shutdownNow(); + + // stop monitorThread (interrupt and wait) + monitorThread.interrupt(); + try { + monitorThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + + + // ---------------------- helper ---------------------- + + public ReturnT callback(List callbackParamList) { + + callbackThreadPool.execute(new Runnable() { + @Override + public void run() { + for (HandleCallbackParam handleCallbackParam : callbackParamList) { + ReturnT callbackResult = callback(handleCallbackParam); + logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}", + (callbackResult.getCode() == ReturnT.SUCCESS_CODE ? "success" : "fail"), handleCallbackParam, callbackResult); + } + } + }); + + return ReturnT.SUCCESS; + } + + private ReturnT callback(HandleCallbackParam handleCallbackParam) { + // valid log item + XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(handleCallbackParam.getLogId()); + if (log == null) { + return new ReturnT(ReturnT.FAIL_CODE, "log item not found."); + } + if (log.getHandleCode() > 0) { + return new ReturnT(ReturnT.FAIL_CODE, "log repeate callback."); // avoid repeat callback, trigger child job etc + } + + // handle msg + StringBuffer handleMsg = new StringBuffer(); + if (log.getHandleMsg() != null) { + handleMsg.append(log.getHandleMsg()).append("
"); + } + if (handleCallbackParam.getHandleMsg() != null) { + handleMsg.append(handleCallbackParam.getHandleMsg()); + } + + // success, save log + log.setHandleTime(new Date()); + log.setHandleCode(handleCallbackParam.getHandleCode()); + log.setHandleMsg(handleMsg.toString()); + XxlJobCompleter.updateHandleInfoAndFinish(log); + + return ReturnT.SUCCESS; + } + + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java new file mode 100644 index 0000000..dfebc87 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java @@ -0,0 +1,112 @@ +package com.xxl.job.admin.core.thread; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; +import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +import com.xxl.job.admin.core.util.I18nUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * job monitor instance + * + * @author xuxueli 2015-9-1 18:05:56 + */ +public class JobFailMonitorHelper { + private static Logger logger = LoggerFactory.getLogger(JobFailMonitorHelper.class); + + private static JobFailMonitorHelper instance = new JobFailMonitorHelper(); + + public static JobFailMonitorHelper getInstance() { + return instance; + } + + // ---------------------- monitor ---------------------- + + private Thread monitorThread; + private volatile boolean toStop = false; + + public void start() { + monitorThread = new Thread(new Runnable() { + + @Override + public void run() { + + // monitor + while (!toStop) { + try { + + List failLogIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findFailJobLogIds(1000); + if (failLogIds != null && !failLogIds.isEmpty()) { + for (long failLogId : failLogIds) { + + // lock log + int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, 0, -1); + if (lockRet < 1) { + continue; + } + XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(failLogId); + XxlJobInfo info = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(log.getJobId()); + + // 1、fail retry monitor + if (log.getExecutorFailRetryCount() > 0) { + JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount() - 1), log.getExecutorShardingParam(), log.getExecutorParam(), null); + String retryMsg = "

>>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_type_retry") + "<<<<<<<<<<<
"; + log.setTriggerMsg(log.getTriggerMsg() + retryMsg); + XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(log); + } + + // 2、fail alarm monitor + int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败 + if (info != null) { + boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log); + newAlarmStatus = alarmResult ? 2 : 3; + } else { + newAlarmStatus = 1; + } + + XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, -1, newAlarmStatus); + } + } + + } catch (Exception e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e); + } + } + + try { + TimeUnit.SECONDS.sleep(10); + } catch (Exception e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop"); + + } + }); + monitorThread.setDaemon(true); + monitorThread.setName("xxl-job, admin JobFailMonitorHelper"); + monitorThread.start(); + } + + public void toStop() { + toStop = true; + // interrupt and wait + monitorThread.interrupt(); + try { + monitorThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java new file mode 100644 index 0000000..942f752 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java @@ -0,0 +1,154 @@ +package com.xxl.job.admin.core.thread; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobLogReport; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * job log report helper + * + * @author xuxueli 2019-11-22 + */ +public class JobLogReportHelper { + private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class); + + private static JobLogReportHelper instance = new JobLogReportHelper(); + + public static JobLogReportHelper getInstance() { + return instance; + } + + + private Thread logrThread; + private volatile boolean toStop = false; + + public void start() { + logrThread = new Thread(new Runnable() { + + @Override + public void run() { + + // last clean log time + long lastCleanLogTime = 0; + + + while (!toStop) { + + // 1、log-report refresh: refresh log report in 3 days + try { + + for (int i = 0; i < 3; i++) { + + // today + Calendar itemDay = Calendar.getInstance(); + itemDay.add(Calendar.DAY_OF_MONTH, -i); + itemDay.set(Calendar.HOUR_OF_DAY, 0); + itemDay.set(Calendar.MINUTE, 0); + itemDay.set(Calendar.SECOND, 0); + itemDay.set(Calendar.MILLISECOND, 0); + + Date todayFrom = itemDay.getTime(); + + itemDay.set(Calendar.HOUR_OF_DAY, 23); + itemDay.set(Calendar.MINUTE, 59); + itemDay.set(Calendar.SECOND, 59); + itemDay.set(Calendar.MILLISECOND, 999); + + Date todayTo = itemDay.getTime(); + + // refresh log-report every minute + XxlJobLogReport xxlJobLogReport = new XxlJobLogReport(); + xxlJobLogReport.setTriggerDay(todayFrom); + xxlJobLogReport.setRunningCount(0); + xxlJobLogReport.setSucCount(0); + xxlJobLogReport.setFailCount(0); + + Map triggerCountMap = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLogReport(todayFrom, todayTo); + if (triggerCountMap != null && triggerCountMap.size() > 0) { + int triggerDayCount = triggerCountMap.containsKey("triggerDayCount") ? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCount"))) : 0; + int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning") ? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountRunning"))) : 0; + int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc") ? Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountSuc"))) : 0; + int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc; + + xxlJobLogReport.setRunningCount(triggerDayCountRunning); + xxlJobLogReport.setSucCount(triggerDayCountSuc); + xxlJobLogReport.setFailCount(triggerDayCountFail); + } + + // do refresh + int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().update(xxlJobLogReport); + if (ret < 1) { + XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport); + } + } + + } catch (Exception e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e); + } + } + + // 2、log-clean: switch open & once each day + if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays() > 0 + && System.currentTimeMillis() - lastCleanLogTime > 24 * 60 * 60 * 1000) { + + // expire-time + Calendar expiredDay = Calendar.getInstance(); + expiredDay.add(Calendar.DAY_OF_MONTH, -1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays()); + expiredDay.set(Calendar.HOUR_OF_DAY, 0); + expiredDay.set(Calendar.MINUTE, 0); + expiredDay.set(Calendar.SECOND, 0); + expiredDay.set(Calendar.MILLISECOND, 0); + Date clearBeforeTime = expiredDay.getTime(); + + // clean expired log + List logIds = null; + do { + logIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findClearLogIds(0, 0, clearBeforeTime, 0, 1000); + if (logIds != null && logIds.size() > 0) { + XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().clearLog(logIds); + } + } while (logIds != null && logIds.size() > 0); + + // update clean time + lastCleanLogTime = System.currentTimeMillis(); + } + + try { + TimeUnit.MINUTES.sleep(1); + } catch (Exception e) { + if (!toStop) { + logger.error(e.getMessage(), e); + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, job log report thread stop"); + + } + }); + logrThread.setDaemon(true); + logrThread.setName("xxl-job, admin JobLogReportHelper"); + logrThread.start(); + } + + public void toStop() { + toStop = true; + // interrupt and wait + logrThread.interrupt(); + try { + logrThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java new file mode 100644 index 0000000..681b684 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java @@ -0,0 +1,206 @@ +package com.xxl.job.admin.core.thread; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobRegistry; +import com.xxl.job.core.biz.model.RegistryParam; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.enums.RegistryConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; + +import java.util.*; +import java.util.concurrent.*; + +/** + * job registry instance + * + * @author xuxueli 2016-10-02 19:10:24 + */ +public class JobRegistryHelper { + private static Logger logger = LoggerFactory.getLogger(JobRegistryHelper.class); + + private static JobRegistryHelper instance = new JobRegistryHelper(); + + public static JobRegistryHelper getInstance() { + return instance; + } + + private ThreadPoolExecutor registryOrRemoveThreadPool = null; + private Thread registryMonitorThread; + private volatile boolean toStop = false; + + public void start() { + + // for registry or remove + registryOrRemoveThreadPool = new ThreadPoolExecutor( + 2, + 10, + 30L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(2000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode()); + } + }, + new RejectedExecutionHandler() { + @Override + public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { + r.run(); + logger.warn(">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now)."); + } + }); + + // for monitor + registryMonitorThread = new Thread(new Runnable() { + @Override + public void run() { + while (!toStop) { + try { + // auto registry group + List groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0); + if (groupList != null && !groupList.isEmpty()) { + + // remove dead address (admin/executor) + List ids = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findDead(RegistryConfig.DEAD_TIMEOUT, new Date()); + if (ids != null && ids.size() > 0) { + XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(ids); + } + + // fresh online address (admin/executor) + HashMap> appAddressMap = new HashMap>(); + List list = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT, new Date()); + if (list != null) { + for (XxlJobRegistry item : list) { + if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) { + String appname = item.getRegistryKey(); + List registryList = appAddressMap.get(appname); + if (registryList == null) { + registryList = new ArrayList(); + } + + if (!registryList.contains(item.getRegistryValue())) { + registryList.add(item.getRegistryValue()); + } + appAddressMap.put(appname, registryList); + } + } + } + + // fresh group address + for (XxlJobGroup group : groupList) { + List registryList = appAddressMap.get(group.getAppname()); + String addressListStr = null; + if (registryList != null && !registryList.isEmpty()) { + Collections.sort(registryList); + StringBuilder addressListSB = new StringBuilder(); + for (String item : registryList) { + addressListSB.append(item).append(","); + } + addressListStr = addressListSB.toString(); + addressListStr = addressListStr.substring(0, addressListStr.length() - 1); + } + group.setAddressList(addressListStr); + group.setUpdateTime(new Date()); + + XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().update(group); + } + } + } catch (Exception e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e); + } + } + try { + TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT); + } catch (InterruptedException e) { + if (!toStop) { + logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e); + } + } + } + logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop"); + } + }); + registryMonitorThread.setDaemon(true); + registryMonitorThread.setName("xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread"); + registryMonitorThread.start(); + } + + public void toStop() { + toStop = true; + + // stop registryOrRemoveThreadPool + registryOrRemoveThreadPool.shutdownNow(); + + // stop monitir (interrupt and wait) + registryMonitorThread.interrupt(); + try { + registryMonitorThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + + + // ---------------------- helper ---------------------- + + public ReturnT registry(RegistryParam registryParam) { + + // valid + if (!StringUtils.hasText(registryParam.getRegistryGroup()) + || !StringUtils.hasText(registryParam.getRegistryKey()) + || !StringUtils.hasText(registryParam.getRegistryValue())) { + return new ReturnT(ReturnT.FAIL_CODE, "Illegal Argument."); + } + + // async execute + registryOrRemoveThreadPool.execute(new Runnable() { + @Override + public void run() { + int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date()); + if (ret < 1) { + XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date()); + + // fresh + freshGroupRegistryInfo(registryParam); + } + } + }); + + return ReturnT.SUCCESS; + } + + public ReturnT registryRemove(RegistryParam registryParam) { + + // valid + if (!StringUtils.hasText(registryParam.getRegistryGroup()) + || !StringUtils.hasText(registryParam.getRegistryKey()) + || !StringUtils.hasText(registryParam.getRegistryValue())) { + return new ReturnT(ReturnT.FAIL_CODE, "Illegal Argument."); + } + + // async execute + registryOrRemoveThreadPool.execute(new Runnable() { + @Override + public void run() { + int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue()); + if (ret > 0) { + // fresh + freshGroupRegistryInfo(registryParam); + } + } + }); + + return ReturnT.SUCCESS; + } + + private void freshGroupRegistryInfo(RegistryParam registryParam) { + // Under consideration, prevent affecting core tables + } + + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java new file mode 100644 index 0000000..69ffdb3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java @@ -0,0 +1,370 @@ +package com.xxl.job.admin.core.thread; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.cron.CronExpression; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum; +import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum; +import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +/** + * @author xuxueli 2019-05-21 + */ +public class JobScheduleHelper { + private static Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class); + + private static JobScheduleHelper instance = new JobScheduleHelper(); + + public static JobScheduleHelper getInstance() { + return instance; + } + + public static final long PRE_READ_MS = 5000; // pre read + + private Thread scheduleThread; + private Thread ringThread; + private volatile boolean scheduleThreadToStop = false; + private volatile boolean ringThreadToStop = false; + private volatile static Map> ringData = new ConcurrentHashMap<>(); + + public void start() { + + // schedule thread + scheduleThread = new Thread(new Runnable() { + @Override + public void run() { + + try { + TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis() % 1000); + } catch (InterruptedException e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + logger.info(">>>>>>>>> init xxl-job admin scheduler success."); + + // pre-read count: treadpool-size * trigger-qps (each trigger cost 50ms, qps = 1000/50 = 20) + int preReadCount = (XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax() + XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax()) * 20; + + while (!scheduleThreadToStop) { + + // Scan Job + long start = System.currentTimeMillis(); + + Connection conn = null; + Boolean connAutoCommit = null; + PreparedStatement preparedStatement = null; + + boolean preReadSuc = true; + try { + + conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection(); + connAutoCommit = conn.getAutoCommit(); + conn.setAutoCommit(false); + + preparedStatement = conn.prepareStatement("select * from xxl_job_lock where lock_name = 'schedule_lock' for update"); + preparedStatement.execute(); + + // tx start + + // 1、pre read + long nowTime = System.currentTimeMillis(); + List scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount); + if (scheduleList != null && scheduleList.size() > 0) { + // 2、push time-ring + for (XxlJobInfo jobInfo : scheduleList) { + + // time-ring jump + if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) { + // 2.1、trigger-expire > 5s:pass && make next-trigger-time + logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId()); + + // 1、misfire match + MisfireStrategyEnum misfireStrategyEnum = MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), MisfireStrategyEnum.DO_NOTHING); + if (MisfireStrategyEnum.FIRE_ONCE_NOW == misfireStrategyEnum) { + // FIRE_ONCE_NOW 》 trigger + JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.MISFIRE, -1, null, null, null); + logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId()); + } + + // 2、fresh next + refreshNextValidTime(jobInfo, new Date()); + + } else if (nowTime > jobInfo.getTriggerNextTime()) { + // 2.2、trigger-expire < 5s:direct-trigger && make next-trigger-time + + // 1、trigger + JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null, null); + logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId()); + + // 2、fresh next + refreshNextValidTime(jobInfo, new Date()); + + // next-trigger-time in 5s, pre-read again + if (jobInfo.getTriggerStatus() == 1 && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) { + + // 1、make ring second + int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60); + + // 2、push time ring + pushTimeRing(ringSecond, jobInfo.getId()); + + // 3、fresh next + refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime())); + + } + + } else { + // 2.3、trigger-pre-read:time-ring trigger && make next-trigger-time + + // 1、make ring second + int ringSecond = (int) ((jobInfo.getTriggerNextTime() / 1000) % 60); + + // 2、push time ring + pushTimeRing(ringSecond, jobInfo.getId()); + + // 3、fresh next + refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime())); + + } + + } + + // 3、update trigger info + for (XxlJobInfo jobInfo : scheduleList) { + XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo); + } + + } else { + preReadSuc = false; + } + + // tx stop + + + } catch (Exception e) { + if (!scheduleThreadToStop) { + logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}", e); + } + } finally { + + // commit + if (conn != null) { + try { + conn.commit(); + } catch (SQLException e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + try { + conn.setAutoCommit(connAutoCommit); + } catch (SQLException e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + try { + conn.close(); + } catch (SQLException e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + } + + // close PreparedStatement + if (null != preparedStatement) { + try { + preparedStatement.close(); + } catch (SQLException e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + } + } + long cost = System.currentTimeMillis() - start; + + + // Wait seconds, align second + if (cost < 1000) { // scan-overtime, not wait + try { + // pre-read period: success > scan each second; fail > skip this period; + TimeUnit.MILLISECONDS.sleep((preReadSuc ? 1000 : PRE_READ_MS) - System.currentTimeMillis() % 1000); + } catch (InterruptedException e) { + if (!scheduleThreadToStop) { + logger.error(e.getMessage(), e); + } + } + } + + } + + logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop"); + } + }); + scheduleThread.setDaemon(true); + scheduleThread.setName("xxl-job, admin JobScheduleHelper#scheduleThread"); + scheduleThread.start(); + + + // ring thread + ringThread = new Thread(new Runnable() { + @Override + public void run() { + + while (!ringThreadToStop) { + + // align second + try { + TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000); + } catch (InterruptedException e) { + if (!ringThreadToStop) { + logger.error(e.getMessage(), e); + } + } + + try { + // second data + List ringItemData = new ArrayList<>(); + int nowSecond = Calendar.getInstance().get(Calendar.SECOND); // 避免处理耗时太长,跨过刻度,向前校验一个刻度; + for (int i = 0; i < 2; i++) { + List tmpData = ringData.remove((nowSecond + 60 - i) % 60); + if (tmpData != null) { + ringItemData.addAll(tmpData); + } + } + + // ring trigger + logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData)); + if (ringItemData.size() > 0) { + // do trigger + for (int jobId : ringItemData) { + // do trigger + JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null); + } + // clear + ringItemData.clear(); + } + } catch (Exception e) { + if (!ringThreadToStop) { + logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e); + } + } + } + logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop"); + } + }); + ringThread.setDaemon(true); + ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread"); + ringThread.start(); + } + + private void refreshNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception { + Date nextValidTime = generateNextValidTime(jobInfo, fromTime); + if (nextValidTime != null) { + jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime()); + jobInfo.setTriggerNextTime(nextValidTime.getTime()); + } else { + jobInfo.setTriggerStatus(0); + jobInfo.setTriggerLastTime(0); + jobInfo.setTriggerNextTime(0); + logger.warn(">>>>>>>>>>> xxl-job, refreshNextValidTime fail for job: jobId={}, scheduleType={}, scheduleConf={}", + jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf()); + } + } + + private void pushTimeRing(int ringSecond, int jobId) { + // push async ring + List ringItemData = ringData.get(ringSecond); + if (ringItemData == null) { + ringItemData = new ArrayList(); + ringData.put(ringSecond, ringItemData); + } + ringItemData.add(jobId); + + logger.debug(">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData)); + } + + public void toStop() { + + // 1、stop schedule + scheduleThreadToStop = true; + try { + TimeUnit.SECONDS.sleep(1); // wait + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + if (scheduleThread.getState() != Thread.State.TERMINATED) { + // interrupt and wait + scheduleThread.interrupt(); + try { + scheduleThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + + // if has ring data + boolean hasRingData = false; + if (!ringData.isEmpty()) { + for (int second : ringData.keySet()) { + List tmpData = ringData.get(second); + if (tmpData != null && tmpData.size() > 0) { + hasRingData = true; + break; + } + } + } + if (hasRingData) { + try { + TimeUnit.SECONDS.sleep(8); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + + // stop ring (wait job-in-memory stop) + ringThreadToStop = true; + try { + TimeUnit.SECONDS.sleep(1); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + if (ringThread.getState() != Thread.State.TERMINATED) { + // interrupt and wait + ringThread.interrupt(); + try { + ringThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + + logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper stop"); + } + + + // ---------------------- tools ---------------------- + public static Date generateNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception { + ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); + if (ScheduleTypeEnum.CRON == scheduleTypeEnum) { + Date nextValidTime = new CronExpression(jobInfo.getScheduleConf()).getNextValidTimeAfter(fromTime); + return nextValidTime; + } else if (ScheduleTypeEnum.FIX_RATE == scheduleTypeEnum /*|| ScheduleTypeEnum.FIX_DELAY == scheduleTypeEnum*/) { + return new Date(fromTime.getTime() + Integer.valueOf(jobInfo.getScheduleConf()) * 1000); + } + return null; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java new file mode 100644 index 0000000..775b916 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java @@ -0,0 +1,148 @@ +package com.xxl.job.admin.core.thread; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.trigger.TriggerTypeEnum; +import com.xxl.job.admin.core.trigger.XxlJobTrigger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * job trigger thread pool helper + * + * @author xuxueli 2018-07-03 21:08:07 + */ +public class JobTriggerPoolHelper { + private static Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class); + + + // ---------------------- trigger pool ---------------------- + + // fast/slow thread pool + private ThreadPoolExecutor fastTriggerPool = null; + private ThreadPoolExecutor slowTriggerPool = null; + + public void start() { + fastTriggerPool = new ThreadPoolExecutor( + 10, + XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(), + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(1000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode()); + } + }); + + slowTriggerPool = new ThreadPoolExecutor( + 10, + XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(), + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(2000), + new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode()); + } + }); + } + + + public void stop() { + //triggerPool.shutdown(); + fastTriggerPool.shutdownNow(); + slowTriggerPool.shutdownNow(); + logger.info(">>>>>>>>> xxl-job trigger thread pool shutdown success."); + } + + + // job timeout count + private volatile long minTim = System.currentTimeMillis() / 60000; // ms > min + private volatile ConcurrentMap jobTimeoutCountMap = new ConcurrentHashMap<>(); + + + /** + * add trigger + */ + public void addTrigger(final int jobId, + final TriggerTypeEnum triggerType, + final int failRetryCount, + final String executorShardingParam, + final String executorParam, + final String addressList) { + + // choose thread pool + ThreadPoolExecutor triggerPool_ = fastTriggerPool; + AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId); + if (jobTimeoutCount != null && jobTimeoutCount.get() > 10) { // job-timeout 10 times in 1 min + triggerPool_ = slowTriggerPool; + } + + // trigger + triggerPool_.execute(new Runnable() { + @Override + public void run() { + + long start = System.currentTimeMillis(); + + try { + // do trigger + XxlJobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList); + } catch (Exception e) { + logger.error(e.getMessage(), e); + } finally { + + // check timeout-count-map + long minTim_now = System.currentTimeMillis() / 60000; + if (minTim != minTim_now) { + minTim = minTim_now; + jobTimeoutCountMap.clear(); + } + + // incr timeout-count-map + long cost = System.currentTimeMillis() - start; + if (cost > 500) { // ob-timeout threshold 500ms + AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1)); + if (timeoutCount != null) { + timeoutCount.incrementAndGet(); + } + } + + } + + } + }); + } + + + // ---------------------- helper ---------------------- + + private static JobTriggerPoolHelper helper = new JobTriggerPoolHelper(); + + public static void toStart() { + helper.start(); + } + + public static void toStop() { + helper.stop(); + } + + /** + * @param jobId + * @param triggerType + * @param failRetryCount >=0: use this param + * <0: use param from job info config + * @param executorShardingParam + * @param executorParam null: use job param + * not null: cover job param + */ + public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam, String addressList) { + helper.addTrigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java new file mode 100644 index 0000000..0402a19 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java @@ -0,0 +1,29 @@ +package com.xxl.job.admin.core.trigger; + +import com.xxl.job.admin.core.util.I18nUtil; + +/** + * trigger type enum + * + * @author xuxueli 2018-09-16 04:56:41 + */ +public enum TriggerTypeEnum { + + MANUAL(I18nUtil.getString("jobconf_trigger_type_manual")), + CRON(I18nUtil.getString("jobconf_trigger_type_cron")), + RETRY(I18nUtil.getString("jobconf_trigger_type_retry")), + PARENT(I18nUtil.getString("jobconf_trigger_type_parent")), + API(I18nUtil.getString("jobconf_trigger_type_api")), + MISFIRE(I18nUtil.getString("jobconf_trigger_type_misfire")); + + private TriggerTypeEnum(String title) { + this.title = title; + } + + private String title; + + public String getTitle() { + return title; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java new file mode 100644 index 0000000..ce2914a --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java @@ -0,0 +1,224 @@ +package com.xxl.job.admin.core.trigger; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLog; +import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; +import com.xxl.job.admin.core.scheduler.XxlJobScheduler; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.biz.model.TriggerParam; +import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +import com.xxl.job.core.util.IpUtil; +import com.xxl.job.core.util.ThrowableUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +/** + * xxl-job trigger + * Created by xuxueli on 17/7/13. + */ +public class XxlJobTrigger { + private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class); + + /** + * trigger job + * + * @param jobId + * @param triggerType + * @param failRetryCount >=0: use this param + * <0: use param from job info config + * @param executorShardingParam + * @param executorParam null: use job param + * not null: cover job param + * @param addressList null: use executor addressList + * not null: cover + */ + public static void trigger(int jobId, + TriggerTypeEnum triggerType, + int failRetryCount, + String executorShardingParam, + String executorParam, + String addressList) { + + // load data + XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId); + if (jobInfo == null) { + logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId); + return; + } + if (executorParam != null) { + jobInfo.setExecutorParam(executorParam); + } + int finalFailRetryCount = failRetryCount >= 0 ? failRetryCount : jobInfo.getExecutorFailRetryCount(); + XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(jobInfo.getJobGroup()); + + // cover addressList + if (addressList != null && addressList.trim().length() > 0) { + group.setAddressType(1); + group.setAddressList(addressList.trim()); + } + + // sharding param + int[] shardingParam = null; + if (executorShardingParam != null) { + String[] shardingArr = executorShardingParam.split("/"); + if (shardingArr.length == 2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) { + shardingParam = new int[2]; + shardingParam[0] = Integer.valueOf(shardingArr[0]); + shardingParam[1] = Integer.valueOf(shardingArr[1]); + } + } + if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) + && group.getRegistryList() != null && !group.getRegistryList().isEmpty() + && shardingParam == null) { + for (int i = 0; i < group.getRegistryList().size(); i++) { + processTrigger(group, jobInfo, finalFailRetryCount, triggerType, i, group.getRegistryList().size()); + } + } else { + if (shardingParam == null) { + shardingParam = new int[]{0, 1}; + } + processTrigger(group, jobInfo, finalFailRetryCount, triggerType, shardingParam[0], shardingParam[1]); + } + + } + + private static boolean isNumeric(String str) { + try { + int result = Integer.valueOf(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * @param group job group, registry list may be empty + * @param jobInfo + * @param finalFailRetryCount + * @param triggerType + * @param index sharding index + * @param total sharding index + */ + private static void processTrigger(XxlJobGroup group, XxlJobInfo jobInfo, int finalFailRetryCount, TriggerTypeEnum triggerType, int index, int total) { + + // param + ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION); // block strategy + ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null); // route strategy + String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) ? String.valueOf(index).concat("/").concat(String.valueOf(total)) : null; + + // 1、save log-id + XxlJobLog jobLog = new XxlJobLog(); + jobLog.setJobGroup(jobInfo.getJobGroup()); + jobLog.setJobId(jobInfo.getId()); + jobLog.setTriggerTime(new Date()); + XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().save(jobLog); + logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId()); + + // 2、init trigger-param + TriggerParam triggerParam = new TriggerParam(); + triggerParam.setJobId(jobInfo.getId()); + triggerParam.setExecutorHandler(jobInfo.getExecutorHandler()); + triggerParam.setExecutorParams(jobInfo.getExecutorParam()); + triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); + triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout()); + triggerParam.setLogId(jobLog.getId()); + triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime()); + triggerParam.setGlueType(jobInfo.getGlueType()); + triggerParam.setGlueSource(jobInfo.getGlueSource()); + triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime()); + triggerParam.setBroadcastIndex(index); + triggerParam.setBroadcastTotal(total); + + // 3、init address + String address = null; + ReturnT routeAddressResult = null; + if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) { + if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) { + if (index < group.getRegistryList().size()) { + address = group.getRegistryList().get(index); + } else { + address = group.getRegistryList().get(0); + } + } else { + routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList()); + if (routeAddressResult.getCode() == ReturnT.SUCCESS_CODE) { + address = routeAddressResult.getContent(); + } + } + } else { + routeAddressResult = new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("jobconf_trigger_address_empty")); + } + + // 4、trigger remote executor + ReturnT triggerResult = null; + if (address != null) { + triggerResult = runExecutor(triggerParam, address); + } else { + triggerResult = new ReturnT(ReturnT.FAIL_CODE, null); + } + + // 5、collection trigger info + StringBuffer triggerMsgSb = new StringBuffer(); + triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append(":").append(triggerType.getTitle()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":") + .append((group.getAddressType() == 0) ? I18nUtil.getString("jobgroup_field_addressType_0") : I18nUtil.getString("jobgroup_field_addressType_1")); + triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle()); + if (shardingParam != null) { + triggerMsgSb.append("(" + shardingParam + ")"); + } + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_timeout")).append(":").append(jobInfo.getExecutorTimeout()); + triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")).append(":").append(finalFailRetryCount); + + triggerMsgSb.append("

>>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_run") + "<<<<<<<<<<<
") + .append((routeAddressResult != null && routeAddressResult.getMsg() != null) ? routeAddressResult.getMsg() + "

" : "").append(triggerResult.getMsg() != null ? triggerResult.getMsg() : ""); + + // 6、save log trigger-info + jobLog.setExecutorAddress(address); + jobLog.setExecutorHandler(jobInfo.getExecutorHandler()); + jobLog.setExecutorParam(jobInfo.getExecutorParam()); + jobLog.setExecutorShardingParam(shardingParam); + jobLog.setExecutorFailRetryCount(finalFailRetryCount); + //jobLog.setTriggerTime(); + jobLog.setTriggerCode(triggerResult.getCode()); + jobLog.setTriggerMsg(triggerMsgSb.toString()); + XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(jobLog); + + logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); + } + + /** + * run executor + * + * @param triggerParam + * @param address + * @return + */ + public static ReturnT runExecutor(TriggerParam triggerParam, String address) { + ReturnT runResult = null; + try { + ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address); + runResult = executorBiz.run(triggerParam); + } catch (Exception e) { + logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e); + runResult = new ReturnT(ReturnT.FAIL_CODE, ThrowableUtil.toString(e)); + } + + StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":"); + runResultSB.append("
address:").append(address); + runResultSB.append("
code:").append(runResult.getCode()); + runResultSB.append("
msg:").append(runResult.getMsg()); + + runResult.setMsg(runResultSB.toString()); + return runResult; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java new file mode 100644 index 0000000..bb9abd7 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java @@ -0,0 +1,98 @@ +package com.xxl.job.admin.core.util; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Cookie.Util + * + * @author xuxueli 2015-12-12 18:01:06 + */ +public class CookieUtil { + + // 默认缓存时间,单位/秒, 2H + private static final int COOKIE_MAX_AGE = Integer.MAX_VALUE; + // 保存路径,根路径 + private static final String COOKIE_PATH = "/"; + + /** + * 保存 + * + * @param response + * @param key + * @param value + * @param ifRemember + */ + public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) { + int age = ifRemember ? COOKIE_MAX_AGE : -1; + set(response, key, value, null, COOKIE_PATH, age, true); + } + + /** + * 保存 + * + * @param response + * @param key + * @param value + * @param maxAge + */ + private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) { + Cookie cookie = new Cookie(key, value); + if (domain != null) { + cookie.setDomain(domain); + } + cookie.setPath(path); + cookie.setMaxAge(maxAge); + cookie.setHttpOnly(isHttpOnly); + response.addCookie(cookie); + } + + /** + * 查询value + * + * @param request + * @param key + * @return + */ + public static String getValue(HttpServletRequest request, String key) { + Cookie cookie = get(request, key); + if (cookie != null) { + return cookie.getValue(); + } + return null; + } + + /** + * 查询Cookie + * + * @param request + * @param key + */ + private static Cookie get(HttpServletRequest request, String key) { + Cookie[] arr_cookie = request.getCookies(); + if (arr_cookie != null && arr_cookie.length > 0) { + for (Cookie cookie : arr_cookie) { + if (cookie.getName().equals(key)) { + return cookie; + } + } + } + return null; + } + + /** + * 删除Cookie + * + * @param request + * @param response + * @param key + */ + public static void remove(HttpServletRequest request, HttpServletResponse response, String key) { + Cookie cookie = get(request, key); + if (cookie != null) { + set(response, key, "", null, COOKIE_PATH, 0, true); + } + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java new file mode 100644 index 0000000..e90af43 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java @@ -0,0 +1,31 @@ +package com.xxl.job.admin.core.util; + +import freemarker.ext.beans.BeansWrapper; +import freemarker.ext.beans.BeansWrapperBuilder; +import freemarker.template.Configuration; +import freemarker.template.TemplateHashModel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * ftl util + * + * @author xuxueli 2018-01-17 20:37:48 + */ +public class FtlUtil { + private static Logger logger = LoggerFactory.getLogger(FtlUtil.class); + + private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build(); //BeansWrapper.getDefaultInstance(); + + public static TemplateHashModel generateStaticModel(String packageName) { + try { + TemplateHashModel staticModels = wrapper.getStaticModels(); + TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName); + return fileStatics; + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + return null; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java new file mode 100644 index 0000000..4c8cc5c --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java @@ -0,0 +1,80 @@ +package com.xxl.job.admin.core.util; + +import com.xxl.job.admin.core.conf.XxlJobAdminConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.core.io.support.PropertiesLoaderUtils; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +/** + * i18n util + * + * @author xuxueli 2018-01-17 20:39:06 + */ +public class I18nUtil { + private static Logger logger = LoggerFactory.getLogger(I18nUtil.class); + + private static Properties prop = null; + + public static Properties loadI18nProp() { + if (prop != null) { + return prop; + } + try { + // build i18n prop + String i18n = XxlJobAdminConfig.getAdminConfig().getI18n(); + String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n); + + // load prop + Resource resource = new ClassPathResource(i18nFile); + EncodedResource encodedResource = new EncodedResource(resource, "UTF-8"); + prop = PropertiesLoaderUtils.loadProperties(encodedResource); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return prop; + } + + /** + * get val of i18n key + * + * @param key + * @return + */ + public static String getString(String key) { + return loadI18nProp().getProperty(key); + } + + /** + * get mult val of i18n mult key, as json + * + * @param keys + * @return + */ + public static String getMultString(String... keys) { + Map map = new HashMap(); + + Properties prop = loadI18nProp(); + if (keys != null && keys.length > 0) { + for (String key : keys) { + map.put(key, prop.getProperty(key)); + } + } else { + for (String key : prop.stringPropertyNames()) { + map.put(key, prop.getProperty(key)); + } + } + + String json = JacksonUtil.writeValueAsString(map); + return json; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java new file mode 100644 index 0000000..0312b74 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java @@ -0,0 +1,93 @@ +package com.xxl.job.admin.core.util; + +import com.fasterxml.jackson.core.JsonGenerationException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +/** + * Jackson util + *

+ * 1、obj need private and set/get; + * 2、do not support inner class; + * + * @author xuxueli 2015-9-25 18:02:56 + */ +public class JacksonUtil { + private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class); + + private final static ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + public static ObjectMapper getInstance() { + return OBJECT_MAPPER; + } + + /** + * bean、array、List、Map --> json + * + * @param obj + * @return json string + * @throws Exception + */ + public static String writeValueAsString(Object obj) { + try { + return getInstance().writeValueAsString(obj); + } catch (JsonGenerationException e) { + logger.error(e.getMessage(), e); + } catch (JsonMappingException e) { + logger.error(e.getMessage(), e); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return null; + } + + /** + * string --> bean、Map、List(array) + * + * @param jsonStr + * @param clazz + * @return obj + * @throws Exception + */ + public static T readValue(String jsonStr, Class clazz) { + try { + return getInstance().readValue(jsonStr, clazz); + } catch (JsonParseException e) { + logger.error(e.getMessage(), e); + } catch (JsonMappingException e) { + logger.error(e.getMessage(), e); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return null; + } + + /** + * string --> List... + * + * @param jsonStr + * @param parametrized + * @param parameterClasses + * @param + * @return + */ + public static T readValue(String jsonStr, Class parametrized, Class... parameterClasses) { + try { + JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses); + return getInstance().readValue(jsonStr, javaType); + } catch (JsonParseException e) { + logger.error(e.getMessage(), e); + } catch (JsonMappingException e) { + logger.error(e.getMessage(), e); + } catch (IOException e) { + logger.error(e.getMessage(), e); + } + return null; + } +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java new file mode 100644 index 0000000..6232afa --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java @@ -0,0 +1,134 @@ +package com.xxl.job.admin.core.util; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * local cache tool + * + * @author xuxueli 2018-01-22 21:37:34 + */ +public class LocalCacheUtil { + + private static ConcurrentMap cacheRepository = new ConcurrentHashMap(); // 类型建议用抽象父类,兼容性更好; + + private static class LocalCacheData { + private String key; + private Object val; + private long timeoutTime; + + public LocalCacheData() { + } + + public LocalCacheData(String key, Object val, long timeoutTime) { + this.key = key; + this.val = val; + this.timeoutTime = timeoutTime; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Object getVal() { + return val; + } + + public void setVal(Object val) { + this.val = val; + } + + public long getTimeoutTime() { + return timeoutTime; + } + + public void setTimeoutTime(long timeoutTime) { + this.timeoutTime = timeoutTime; + } + } + + + /** + * set cache + * + * @param key + * @param val + * @param cacheTime + * @return + */ + public static boolean set(String key, Object val, long cacheTime) { + + // clean timeout cache, before set new cache (avoid cache too much) + cleanTimeoutCache(); + + // set new cache + if (key == null || key.trim().length() == 0) { + return false; + } + if (val == null) { + remove(key); + } + if (cacheTime <= 0) { + remove(key); + } + long timeoutTime = System.currentTimeMillis() + cacheTime; + LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime); + cacheRepository.put(localCacheData.getKey(), localCacheData); + return true; + } + + /** + * remove cache + * + * @param key + * @return + */ + public static boolean remove(String key) { + if (key == null || key.trim().length() == 0) { + return false; + } + cacheRepository.remove(key); + return true; + } + + /** + * get cache + * + * @param key + * @return + */ + public static Object get(String key) { + if (key == null || key.trim().length() == 0) { + return null; + } + LocalCacheData localCacheData = cacheRepository.get(key); + if (localCacheData != null && System.currentTimeMillis() < localCacheData.getTimeoutTime()) { + return localCacheData.getVal(); + } else { + remove(key); + return null; + } + } + + /** + * clean timeout cache + * + * @return + */ + public static boolean cleanTimeoutCache() { + if (!cacheRepository.keySet().isEmpty()) { + for (String key : cacheRepository.keySet()) { + LocalCacheData localCacheData = cacheRepository.get(key); + if (localCacheData != null && System.currentTimeMillis() >= localCacheData.getTimeoutTime()) { + cacheRepository.remove(key); + } + } + } + return true; + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java new file mode 100644 index 0000000..b608d9f --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java @@ -0,0 +1,37 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobGroup; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * Created by xuxueli on 16/9/30. + */ +@Mapper +public interface XxlJobGroupDao { + + public List findAll(); + + public List findByAddressType(@Param("addressType") int addressType); + + public int save(XxlJobGroup xxlJobGroup); + + public int update(XxlJobGroup xxlJobGroup); + + public int remove(@Param("id") int id); + + public XxlJobGroup load(@Param("id") int id); + + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("appname") String appname, + @Param("title") String title); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("appname") String appname, + @Param("title") String title); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java new file mode 100644 index 0000000..e01dd11 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java @@ -0,0 +1,51 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobInfo; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + + +/** + * job info + * + * @author xuxueli 2016-1-12 18:03:45 + */ +@Mapper +public interface XxlJobInfoDao { + + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("triggerStatus") int triggerStatus, + @Param("jobDesc") String jobDesc, + @Param("executorHandler") String executorHandler, + @Param("author") String author); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("triggerStatus") int triggerStatus, + @Param("jobDesc") String jobDesc, + @Param("executorHandler") String executorHandler, + @Param("author") String author); + + public int save(XxlJobInfo info); + + public XxlJobInfo loadById(@Param("id") int id); + + public int update(XxlJobInfo xxlJobInfo); + + public int delete(@Param("id") long id); + + public List getJobsByGroup(@Param("jobGroup") int jobGroup); + + public int findAllCount(); + + public List scheduleJobQuery(@Param("maxNextTime") long maxNextTime, @Param("pagesize") int pagesize); + + public int scheduleUpdate(XxlJobInfo xxlJobInfo); + + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java new file mode 100644 index 0000000..7beaf75 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java @@ -0,0 +1,65 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobLog; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * job log + * + * @author xuxueli 2016-1-12 18:03:06 + */ +@Mapper +public interface XxlJobLogDao { + + // exist jobId not use jobGroup, not exist use jobGroup + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("jobId") int jobId, + @Param("triggerTimeStart") Date triggerTimeStart, + @Param("triggerTimeEnd") Date triggerTimeEnd, + @Param("logStatus") int logStatus); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("jobGroup") int jobGroup, + @Param("jobId") int jobId, + @Param("triggerTimeStart") Date triggerTimeStart, + @Param("triggerTimeEnd") Date triggerTimeEnd, + @Param("logStatus") int logStatus); + + public XxlJobLog load(@Param("id") long id); + + public long save(XxlJobLog xxlJobLog); + + public int updateTriggerInfo(XxlJobLog xxlJobLog); + + public int updateHandleInfo(XxlJobLog xxlJobLog); + + public int delete(@Param("jobId") int jobId); + + public Map findLogReport(@Param("from") Date from, + @Param("to") Date to); + + public List findClearLogIds(@Param("jobGroup") int jobGroup, + @Param("jobId") int jobId, + @Param("clearBeforeTime") Date clearBeforeTime, + @Param("clearBeforeNum") int clearBeforeNum, + @Param("pagesize") int pagesize); + + public int clearLog(@Param("logIds") List logIds); + + public List findFailJobLogIds(@Param("pagesize") int pagesize); + + public int updateAlarmStatus(@Param("logId") long logId, + @Param("oldAlarmStatus") int oldAlarmStatus, + @Param("newAlarmStatus") int newAlarmStatus); + + public List findLostJobIds(@Param("losedTime") Date losedTime); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java new file mode 100644 index 0000000..8b2b414 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java @@ -0,0 +1,25 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobLogGlue; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * job log for glue + * + * @author xuxueli 2016-5-19 18:04:56 + */ +@Mapper +public interface XxlJobLogGlueDao { + + public int save(XxlJobLogGlue xxlJobLogGlue); + + public List findByJobId(@Param("jobId") int jobId); + + public int removeOld(@Param("jobId") int jobId, @Param("limit") int limit); + + public int deleteByJobId(@Param("jobId") int jobId); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java new file mode 100644 index 0000000..d4e0381 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java @@ -0,0 +1,27 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobLogReport; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * job log + * + * @author xuxueli 2019-11-22 + */ +@Mapper +public interface XxlJobLogReportDao { + + public int save(XxlJobLogReport xxlJobLogReport); + + public int update(XxlJobLogReport xxlJobLogReport); + + public List queryLogReport(@Param("triggerDayFrom") Date triggerDayFrom, + @Param("triggerDayTo") Date triggerDayTo); + + public XxlJobLogReport queryLogReportTotal(); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java new file mode 100644 index 0000000..a68e12c --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java @@ -0,0 +1,38 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobRegistry; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.Date; +import java.util.List; + +/** + * Created by xuxueli on 16/9/30. + */ +@Mapper +public interface XxlJobRegistryDao { + + public List findDead(@Param("timeout") int timeout, + @Param("nowTime") Date nowTime); + + public int removeDead(@Param("ids") List ids); + + public List findAll(@Param("timeout") int timeout, + @Param("nowTime") Date nowTime); + + public int registryUpdate(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue, + @Param("updateTime") Date updateTime); + + public int registrySave(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue, + @Param("updateTime") Date updateTime); + + public int registryDelete(@Param("registryGroup") String registryGroup, + @Param("registryKey") String registryKey, + @Param("registryValue") String registryValue); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java new file mode 100644 index 0000000..064ce19 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java @@ -0,0 +1,33 @@ +package com.xxl.job.admin.dao; + +import com.xxl.job.admin.core.model.XxlJobUser; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * @author xuxueli 2019-05-04 16:44:59 + */ +@Mapper +public interface XxlJobUserDao { + + public List pageList(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("username") String username, + @Param("role") int role); + + public int pageListCount(@Param("offset") int offset, + @Param("pagesize") int pagesize, + @Param("username") String username, + @Param("role") int role); + + public XxlJobUser loadByUserName(@Param("username") String username); + + public int save(XxlJobUser xxlJobUser); + + public int update(XxlJobUser xxlJobUser); + + public int delete(@Param("id") int id); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java new file mode 100644 index 0000000..0937b8e --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java @@ -0,0 +1,108 @@ +package com.xxl.job.admin.service; + +import com.xxl.job.admin.core.model.XxlJobUser; +import com.xxl.job.admin.core.util.CookieUtil; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.core.util.JacksonUtil; +import com.xxl.job.admin.dao.XxlJobUserDao; +import com.xxl.job.core.biz.model.ReturnT; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.DigestUtils; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.math.BigInteger; + +/** + * @author xuxueli 2019-05-04 22:13:264 + */ +@Configuration +public class LoginService { + + public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY"; + + @Resource + private XxlJobUserDao xxlJobUserDao; + + + private String makeToken(XxlJobUser xxlJobUser) { + String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser); + String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16); + return tokenHex; + } + + private XxlJobUser parseToken(String tokenHex) { + XxlJobUser xxlJobUser = null; + if (tokenHex != null) { + String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5) + xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class); + } + return xxlJobUser; + } + + + public ReturnT login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember) { + + // param + if (username == null || username.trim().length() == 0 || password == null || password.trim().length() == 0) { + return new ReturnT(500, I18nUtil.getString("login_param_empty")); + } + + // valid passowrd + XxlJobUser xxlJobUser = xxlJobUserDao.loadByUserName(username); + if (xxlJobUser == null) { + return new ReturnT(500, I18nUtil.getString("login_param_unvalid")); + } + String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes()); + if (!passwordMd5.equals(xxlJobUser.getPassword())) { + return new ReturnT(500, I18nUtil.getString("login_param_unvalid")); + } + + String loginToken = makeToken(xxlJobUser); + + // do login + CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember); + return ReturnT.SUCCESS; + } + + /** + * logout + * + * @param request + * @param response + */ + public ReturnT logout(HttpServletRequest request, HttpServletResponse response) { + CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY); + return ReturnT.SUCCESS; + } + + /** + * logout + * + * @param request + * @return + */ + public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response) { + String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY); + if (cookieToken != null) { + XxlJobUser cookieUser = null; + try { + cookieUser = parseToken(cookieToken); + } catch (Exception e) { + logout(request, response); + } + if (cookieUser != null) { + XxlJobUser dbUser = xxlJobUserDao.loadByUserName(cookieUser.getUsername()); + if (dbUser != null) { + if (cookieUser.getPassword().equals(dbUser.getPassword())) { + return dbUser; + } + } + } + } + return null; + } + + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java new file mode 100644 index 0000000..43c2eff --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java @@ -0,0 +1,87 @@ +package com.xxl.job.admin.service; + + +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.core.biz.model.ReturnT; + +import java.util.Date; +import java.util.Map; + +/** + * core job action for xxl-job + * + * @author xuxueli 2016-5-28 15:30:33 + */ +public interface XxlJobService { + + /** + * page list + * + * @param start + * @param length + * @param jobGroup + * @param jobDesc + * @param executorHandler + * @param author + * @return + */ + public Map pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author); + + /** + * add job + * + * @param jobInfo + * @return + */ + public ReturnT add(XxlJobInfo jobInfo); + + /** + * update job + * + * @param jobInfo + * @return + */ + public ReturnT update(XxlJobInfo jobInfo); + + /** + * remove job + * * + * + * @param id + * @return + */ + public ReturnT remove(int id); + + /** + * start job + * + * @param id + * @return + */ + public ReturnT start(int id); + + /** + * stop job + * + * @param id + * @return + */ + public ReturnT stop(int id); + + /** + * dashboard info + * + * @return + */ + public Map dashboardInfo(); + + /** + * chart info + * + * @param startDate + * @param endDate + * @return + */ + public ReturnT> chartInfo(Date startDate, Date endDate); + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java new file mode 100644 index 0000000..3c01e94 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java @@ -0,0 +1,35 @@ +package com.xxl.job.admin.service.impl; + +import com.xxl.job.admin.core.thread.JobCompleteHelper; +import com.xxl.job.admin.core.thread.JobRegistryHelper; +import com.xxl.job.core.biz.AdminBiz; +import com.xxl.job.core.biz.model.HandleCallbackParam; +import com.xxl.job.core.biz.model.RegistryParam; +import com.xxl.job.core.biz.model.ReturnT; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @author xuxueli 2017-07-27 21:54:20 + */ +@Service +public class AdminBizImpl implements AdminBiz { + + + @Override + public ReturnT callback(List callbackParamList) { + return JobCompleteHelper.getInstance().callback(callbackParamList); + } + + @Override + public ReturnT registry(RegistryParam registryParam) { + return JobRegistryHelper.getInstance().registry(registryParam); + } + + @Override + public ReturnT registryRemove(RegistryParam registryParam) { + return JobRegistryHelper.getInstance().registryRemove(registryParam); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java new file mode 100644 index 0000000..454610c --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java @@ -0,0 +1,435 @@ +package com.xxl.job.admin.service.impl; + +import com.xxl.job.admin.core.cron.CronExpression; +import com.xxl.job.admin.core.model.XxlJobGroup; +import com.xxl.job.admin.core.model.XxlJobInfo; +import com.xxl.job.admin.core.model.XxlJobLogReport; +import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; +import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum; +import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum; +import com.xxl.job.admin.core.thread.JobScheduleHelper; +import com.xxl.job.admin.core.util.I18nUtil; +import com.xxl.job.admin.dao.*; +import com.xxl.job.admin.service.XxlJobService; +import com.xxl.job.core.biz.model.ReturnT; +import com.xxl.job.core.enums.ExecutorBlockStrategyEnum; +import com.xxl.job.core.glue.GlueTypeEnum; +import com.xxl.job.core.util.DateUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.text.MessageFormat; +import java.util.*; + +/** + * core job action for xxl-job + * + * @author xuxueli 2016-5-28 15:30:33 + */ +@Service +public class XxlJobServiceImpl implements XxlJobService { + private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class); + + @Resource + private XxlJobGroupDao xxlJobGroupDao; + @Resource + private XxlJobInfoDao xxlJobInfoDao; + @Resource + public XxlJobLogDao xxlJobLogDao; + @Resource + private XxlJobLogGlueDao xxlJobLogGlueDao; + @Resource + private XxlJobLogReportDao xxlJobLogReportDao; + + @Override + public Map pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @Override + public ReturnT add(XxlJobInfo jobInfo) { + + // valid base + XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup()); + if (group == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose") + I18nUtil.getString("jobinfo_field_jobgroup"))); + } + if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc"))); + } + if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author"))); + } + + // valid trigger + ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); + if (scheduleTypeEnum == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + if (scheduleTypeEnum == ScheduleTypeEnum.CRON) { + if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) { + return new ReturnT(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid")); + } + } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) { + if (jobInfo.getScheduleConf() == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type"))); + } + try { + int fixSecond = Integer.valueOf(jobInfo.getScheduleConf()); + if (fixSecond < 1) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + } catch (Exception e) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + } + + // valid job + if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype") + I18nUtil.getString("system_unvalid"))); + } + if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler() == null || jobInfo.getExecutorHandler().trim().length() == 0)) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + "JobHandler")); + } + // 》fix "\r" in shell + if (GlueTypeEnum.GLUE_SHELL == GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource() != null) { + jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", "")); + } + + // valid advanced + if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid"))); + } + if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid"))); + } + if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid"))); + } + + // 》ChildJobId valid + if (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) { + String[] childJobIds = jobInfo.getChildJobId().split(","); + for (String childJobIdItem : childJobIds) { + if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem)); + if (childJobInfo == null) { + return new ReturnT(ReturnT.FAIL_CODE, + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_unvalid")), childJobIdItem)); + } + } + + // join , avoid "xxx,," + String temp = ""; + for (String item : childJobIds) { + temp += item + ","; + } + temp = temp.substring(0, temp.length() - 1); + + jobInfo.setChildJobId(temp); + } + + // add in db + jobInfo.setAddTime(new Date()); + jobInfo.setUpdateTime(new Date()); + jobInfo.setGlueUpdatetime(new Date()); + xxlJobInfoDao.save(jobInfo); + if (jobInfo.getId() < 1) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add") + I18nUtil.getString("system_fail"))); + } + + return new ReturnT(String.valueOf(jobInfo.getId())); + } + + private boolean isNumeric(String str) { + try { + int result = Integer.valueOf(str); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + @Override + public ReturnT update(XxlJobInfo jobInfo) { + + // valid base + if (jobInfo.getJobDesc() == null || jobInfo.getJobDesc().trim().length() == 0) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_jobdesc"))); + } + if (jobInfo.getAuthor() == null || jobInfo.getAuthor().trim().length() == 0) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_field_author"))); + } + + // valid trigger + ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null); + if (scheduleTypeEnum == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + if (scheduleTypeEnum == ScheduleTypeEnum.CRON) { + if (jobInfo.getScheduleConf() == null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) { + return new ReturnT(ReturnT.FAIL_CODE, "Cron" + I18nUtil.getString("system_unvalid")); + } + } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) { + if (jobInfo.getScheduleConf() == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + try { + int fixSecond = Integer.valueOf(jobInfo.getScheduleConf()); + if (fixSecond < 1) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + } catch (Exception e) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + } + + // valid advanced + if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy") + I18nUtil.getString("system_unvalid"))); + } + if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy") + I18nUtil.getString("system_unvalid"))); + } + if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy") + I18nUtil.getString("system_unvalid"))); + } + + // 》ChildJobId valid + if (jobInfo.getChildJobId() != null && jobInfo.getChildJobId().trim().length() > 0) { + String[] childJobIds = jobInfo.getChildJobId().split(","); + for (String childJobIdItem : childJobIds) { + if (childJobIdItem != null && childJobIdItem.trim().length() > 0 && isNumeric(childJobIdItem)) { + XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem)); + if (childJobInfo == null) { + return new ReturnT(ReturnT.FAIL_CODE, + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_not_found")), childJobIdItem)); + } + } else { + return new ReturnT(ReturnT.FAIL_CODE, + MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId") + "({0})" + I18nUtil.getString("system_unvalid")), childJobIdItem)); + } + } + + // join , avoid "xxx,," + String temp = ""; + for (String item : childJobIds) { + temp += item + ","; + } + temp = temp.substring(0, temp.length() - 1); + + jobInfo.setChildJobId(temp); + } + + // group valid + XxlJobGroup jobGroup = xxlJobGroupDao.load(jobInfo.getJobGroup()); + if (jobGroup == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_jobgroup") + I18nUtil.getString("system_unvalid"))); + } + + // stage job info + XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId()); + if (exists_jobInfo == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_not_found"))); + } + + // next trigger time (5s后生效,避开预读周期) + long nextTriggerTime = exists_jobInfo.getTriggerNextTime(); + boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf()); + if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) { + try { + Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS)); + if (nextValidTime == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + nextTriggerTime = nextValidTime.getTime(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + } + + exists_jobInfo.setJobGroup(jobInfo.getJobGroup()); + exists_jobInfo.setJobDesc(jobInfo.getJobDesc()); + exists_jobInfo.setAuthor(jobInfo.getAuthor()); + exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail()); + exists_jobInfo.setScheduleType(jobInfo.getScheduleType()); + exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf()); + exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy()); + exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy()); + exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler()); + exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam()); + exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy()); + exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout()); + exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount()); + exists_jobInfo.setChildJobId(jobInfo.getChildJobId()); + exists_jobInfo.setTriggerNextTime(nextTriggerTime); + + exists_jobInfo.setUpdateTime(new Date()); + xxlJobInfoDao.update(exists_jobInfo); + + + return ReturnT.SUCCESS; + } + + @Override + public ReturnT remove(int id) { + XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id); + if (xxlJobInfo == null) { + return ReturnT.SUCCESS; + } + + xxlJobInfoDao.delete(id); + xxlJobLogDao.delete(id); + xxlJobLogGlueDao.deleteByJobId(id); + return ReturnT.SUCCESS; + } + + @Override + public ReturnT start(int id) { + XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id); + + // valid + ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE); + if (ScheduleTypeEnum.NONE == scheduleTypeEnum) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type_none_limit_start"))); + } + + // next trigger time (5s后生效,避开预读周期) + long nextTriggerTime = 0; + try { + Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS)); + if (nextValidTime == null) { + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + nextTriggerTime = nextValidTime.getTime(); + } catch (Exception e) { + logger.error(e.getMessage(), e); + return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid"))); + } + + xxlJobInfo.setTriggerStatus(1); + xxlJobInfo.setTriggerLastTime(0); + xxlJobInfo.setTriggerNextTime(nextTriggerTime); + + xxlJobInfo.setUpdateTime(new Date()); + xxlJobInfoDao.update(xxlJobInfo); + return ReturnT.SUCCESS; + } + + @Override + public ReturnT stop(int id) { + XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id); + + xxlJobInfo.setTriggerStatus(0); + xxlJobInfo.setTriggerLastTime(0); + xxlJobInfo.setTriggerNextTime(0); + + xxlJobInfo.setUpdateTime(new Date()); + xxlJobInfoDao.update(xxlJobInfo); + return ReturnT.SUCCESS; + } + + @Override + public Map dashboardInfo() { + + int jobInfoCount = xxlJobInfoDao.findAllCount(); + int jobLogCount = 0; + int jobLogSuccessCount = 0; + XxlJobLogReport xxlJobLogReport = xxlJobLogReportDao.queryLogReportTotal(); + if (xxlJobLogReport != null) { + jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount(); + jobLogSuccessCount = xxlJobLogReport.getSucCount(); + } + + // executor count + Set executorAddressSet = new HashSet(); + List groupList = xxlJobGroupDao.findAll(); + + if (groupList != null && !groupList.isEmpty()) { + for (XxlJobGroup group : groupList) { + if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) { + executorAddressSet.addAll(group.getRegistryList()); + } + } + } + + int executorCount = executorAddressSet.size(); + + Map dashboardMap = new HashMap(); + dashboardMap.put("jobInfoCount", jobInfoCount); + dashboardMap.put("jobLogCount", jobLogCount); + dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount); + dashboardMap.put("executorCount", executorCount); + return dashboardMap; + } + + @Override + public ReturnT> chartInfo(Date startDate, Date endDate) { + + // process + List triggerDayList = new ArrayList(); + List triggerDayCountRunningList = new ArrayList(); + List triggerDayCountSucList = new ArrayList(); + List triggerDayCountFailList = new ArrayList(); + int triggerCountRunningTotal = 0; + int triggerCountSucTotal = 0; + int triggerCountFailTotal = 0; + + List logReportList = xxlJobLogReportDao.queryLogReport(startDate, endDate); + + if (logReportList != null && logReportList.size() > 0) { + for (XxlJobLogReport item : logReportList) { + String day = DateUtil.formatDate(item.getTriggerDay()); + int triggerDayCountRunning = item.getRunningCount(); + int triggerDayCountSuc = item.getSucCount(); + int triggerDayCountFail = item.getFailCount(); + + triggerDayList.add(day); + triggerDayCountRunningList.add(triggerDayCountRunning); + triggerDayCountSucList.add(triggerDayCountSuc); + triggerDayCountFailList.add(triggerDayCountFail); + + triggerCountRunningTotal += triggerDayCountRunning; + triggerCountSucTotal += triggerDayCountSuc; + triggerCountFailTotal += triggerDayCountFail; + } + } else { + for (int i = -6; i <= 0; i++) { + triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i))); + triggerDayCountRunningList.add(0); + triggerDayCountSucList.add(0); + triggerDayCountFailList.add(0); + } + } + + Map result = new HashMap(); + result.put("triggerDayList", triggerDayList); + result.put("triggerDayCountRunningList", triggerDayCountRunningList); + result.put("triggerDayCountSucList", triggerDayCountSucList); + result.put("triggerDayCountFailList", triggerDayCountFailList); + + result.put("triggerCountRunningTotal", triggerCountRunningTotal); + result.put("triggerCountSucTotal", triggerCountSucTotal); + result.put("triggerCountFailTotal", triggerCountFailTotal); + + return new ReturnT>(result); + } + +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/application-dev.yml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..fcedd6f --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/application-dev.yml @@ -0,0 +1,37 @@ + +--- # 数据库配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://localhost:3306/ry-vue-blog?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai + username: root + password: root + hikari: + auto-commit: true + connection-test-query: SELECT 1 + connection-timeout: 10000 + idle-timeout: 30000 + max-lifetime: 900000 + maximum-pool-size: 30 + minimum-idle: 10 + pool-name: HikariCP + validation-timeout: 1000 + +--- # 邮件配置 +spring: + mail: + from: xxx@qq.com + host: smtp.qq.com + username: xxx@qq.com + password: xxx + port: 25 + properties: + mail: + smtp: + auth: true + socketFactory: + class: javax.net.ssl.SSLSocketFactory + starttls: + enable: true + required: true diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/application-prod.yml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..0b9f691 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/application-prod.yml @@ -0,0 +1,38 @@ + + +--- # 数据库配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://8.130.45.202:3306/ry-vue-blog?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai + username: root + password: root + hikari: + auto-commit: true + connection-test-query: SELECT 1 + connection-timeout: 10000 + idle-timeout: 30000 + max-lifetime: 900000 + maximum-pool-size: 30 + minimum-idle: 10 + pool-name: HikariCP + validation-timeout: 1000 + +--- # 邮件配置 +spring: + mail: + from: xxx@qq.com + host: smtp.qq.com + username: xxx@qq.com + password: xxx + port: 25 + properties: + mail: + smtp: + auth: true + socketFactory: + class: javax.net.ssl.SSLSocketFactory + starttls: + enable: true + required: true diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/application.yml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/application.yml new file mode 100644 index 0000000..6ccbea1 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/application.yml @@ -0,0 +1,47 @@ +--- # server 配置 +server: + port: 9100 + servlet: + context-path: /xxl-job-admin +spring: + application: + name: zhi-xxl-job-admin + profiles: + active: @profiles.active@ + mvc: + servlet: + load-on-startup: 0 + static-path-pattern: /static/** + web: + resources: + static-locations: classpath:/static/ + +--- # mybatis 配置 +mybatis: + mapper-locations: classpath:/mybatis-mapper/*Mapper.xml + +--- # 页面配置 +spring: + freemarker: + charset: UTF-8 + request-context-attribute: request + settings: + number_format: 0.########## + suffix: .ftl + templateLoaderPath: classpath:/templates/ + + +--- # xxljob系统配置 +xxl: + job: + # 鉴权token + accessToken: xxl-job + # 国际化 + i18n: zh_CN + # 日志清理 + logretentiondays: 30 + triggerpool: + fast: + max: 200 + slow: + max: 100 diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/banner.txt b/zhi-extend/zhi-xxl-job-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..a0c5e22 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/banner.txt @@ -0,0 +1,8 @@ +Application Version: ${zhi-vue-plus.version} +Spring Boot Version: ${spring-boot.version} +__ __ _ _ _ _ _ +\ \ / / | | | | | | /\ | | (_) + \ V / __ _| |______ | | ___ | |__ ______ / \ __| |_ __ ___ _ _ __ + > < \ \/ / |______| | |/ _ \| '_ \______/ /\ \ / _` | '_ ` _ \| | '_ \ + / . \ > <| | | |__| | (_) | |_) | / ____ \ (_| | | | | | | | | | | +/_/ \_\/_/\_\_| \____/ \___/|_.__/ /_/ \_\__,_|_| |_| |_|_|_| |_| diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_en.properties b/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_en.properties new file mode 100644 index 0000000..8b3c801 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_en.properties @@ -0,0 +1,276 @@ +admin_name=Scheduling Center +admin_name_full=Distributed Task Scheduling Platform XXL-JOB +admin_version=2.3.1 +admin_i18n=en + +## system +system_tips=System message +system_ok=Confirm +system_close=Close +system_save=Save +system_cancel=Cancel +system_search=Search +system_status=Status +system_opt=Operate +system_please_input=please input +system_please_choose=please choose +system_success=success +system_fail=fail +system_add_suc=add success +system_add_fail=add fail +system_update_suc=update success +system_update_fail=update fail +system_all=All +system_api_error=net error +system_show=Show +system_empty=Empty +system_opt_suc=operate success +system_opt_fail=operate fail +system_opt_edit=Edit +system_opt_del=Delete +system_opt_copy=Copy +system_unvalid=illegal +system_not_found=not exist +system_nav=Navigation +system_digits=digits +system_lengh_limit=Length limit +system_permission_limit=Permission limit +system_welcome=Welcome + +## daterangepicker +daterangepicker_ranges_recent_hour=recent one hour +daterangepicker_ranges_today=today +daterangepicker_ranges_yesterday=yesterday +daterangepicker_ranges_this_month=this month +daterangepicker_ranges_last_month=last month +daterangepicker_ranges_recent_week=recent one week +daterangepicker_ranges_recent_month=recent one month +daterangepicker_custom_name=custom +daterangepicker_custom_starttime=start time +daterangepicker_custom_endtime=end time +daterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat +daterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec + +## dataTable +dataTable_sProcessing=processing... +dataTable_sLengthMenu= _MENU_ records per page +dataTable_sZeroRecords=No matching results +dataTable_sInfo=page _PAGE_ ( Total _PAGES_ pages,_TOTAL_ records ) +dataTable_sInfoEmpty=No Record +dataTable_sInfoFiltered=(Filtered by _MAX_ results) +dataTable_sSearch=Search +dataTable_sEmptyTable=Table data is empty +dataTable_sLoadingRecords=Loading... +dataTable_sFirst=FIRST PAGE +dataTable_sPrevious=Previous Page +dataTable_sNext=Next Page +dataTable_sLast=LAST PAGE +dataTable_sSortAscending=: Rank this column in ascending order +dataTable_sSortDescending=: Rank this column in descending order + +## login +login_btn=Login +login_remember_me=Remember Me +login_username_placeholder=Please enter username +login_password_placeholder=Please enter password +login_username_empty=Please enter username +login_username_lt_4=Username length should not be less than 4 +login_password_empty=Please enter password +login_password_lt_4=Password length should not be less than 4 +login_success=Login success +login_fail=Login fail +login_param_empty=Username or password is empty +login_param_unvalid=Username or password error + +## logout +logout_btn=Logout +logout_confirm=Confirm logout? +logout_success=Logout success +logout_fail=Logout fail + +## change pwd +change_pwd=Change password +change_pwd_suc_to_logout=Change password successful, about to log out login +change_pwd_field_newpwd=new password + +## dashboard +job_dashboard_name=Run report +job_dashboard_job_num=Job number +job_dashboard_job_num_tip=The number of tasks running in the scheduling center +job_dashboard_trigger_num=trigger number +job_dashboard_trigger_num_tip=The number of trigger record scheduled by the scheduling center +job_dashboard_jobgroup_num=Executor number +job_dashboard_jobgroup_num_tip=The number of online executor machines perceived by the scheduling center +job_dashboard_report=Scheduling report +job_dashboard_report_loaddata_fail=Scheduling report load data error +job_dashboard_date_report=Date distribution +job_dashboard_rate_report=Percentage distribution + +## job info +jobinfo_name=Job Manage +jobinfo_job=Job +jobinfo_field_add=Add Job +jobinfo_field_update=Edit Job +jobinfo_field_id=Job ID +jobinfo_field_jobgroup=Executor +jobinfo_field_jobdesc=Job description +jobinfo_field_timeout=Job timeout period +jobinfo_field_gluetype=GLUE Type +jobinfo_field_executorparam=Param +jobinfo_field_author=Author +jobinfo_field_alarmemail=Alarm email +jobinfo_field_alarmemail_placeholder=Please enter alarm mail, if there are more than one comma separated +jobinfo_field_executorRouteStrategy=Route Strategy +jobinfo_field_childJobId=Child Job ID +jobinfo_field_childJobId_placeholder=Please enter the Child job ID, if there are more than one comma separated +jobinfo_field_executorBlockStrategy=Block Strategy +jobinfo_field_executorFailRetryCount=Fail Retry Count +jobinfo_field_executorFailRetryCount_placeholder=Fail Retry Count. effect if greater than zero +jobinfo_script_location=Script location +jobinfo_shard_index=Shard index +jobinfo_shard_total=Shard total +jobinfo_opt_stop=Stop +jobinfo_opt_start=Start +jobinfo_opt_log=Query Log +jobinfo_opt_run=Run Once +jobinfo_opt_run_tips=Please input the address for this trigger. Null will be obtained from the executor +jobinfo_opt_registryinfo=Registry Info +jobinfo_opt_next_time=Next trigger time +jobinfo_glue_remark=Resource Remark +jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100 +jobinfo_glue_rollback=Version Backtrack +jobinfo_glue_jobid_unvalid=Job ID is illegal +jobinfo_glue_gluetype_unvalid=The job is not GLUE Type +jobinfo_field_executorTimeout_placeholder=Job Timeout period,in seconds. effect if greater than zero +schedule_type=Schedule Type +schedule_type_none=None +schedule_type_cron=Cron +schedule_type_fix_rate=Fix rate +schedule_type_fix_delay=Fix delay +schedule_type_none_limit_start=The current schedule type disables startup +misfire_strategy=Misfire strategy +misfire_strategy_do_nothing=Do nothing +misfire_strategy_fire_once_now=Fire once now +jobinfo_conf_base=Base configuration +jobinfo_conf_schedule=Schedule configuration +jobinfo_conf_job=Job configuration +jobinfo_conf_advanced=Advanced configuration + +## job log +joblog_name=Trigger Log +joblog_status=Status +joblog_status_all=All +joblog_status_suc=Success +joblog_status_fail=Fail +joblog_status_running=Running +joblog_field_triggerTime=Trigger Time +joblog_field_triggerCode=Trigger Result +joblog_field_triggerMsg=Trigger Msg +joblog_field_handleTime=Handle Time +joblog_field_handleCode=Handle Result +joblog_field_handleMsg=Trigger Msg +joblog_field_executorAddress=Executor Address +joblog_clean=Clean +joblog_clean_log=Clean Log +joblog_clean_type=Clean Type +joblog_clean_type_1=Clean up log data a month ago +joblog_clean_type_2=Clean up log data three month ago +joblog_clean_type_3=Clean up log data six month ago +joblog_clean_type_4=Clean up log data a year ago +joblog_clean_type_5=Clean up log data a thousand record ago +joblog_clean_type_6=Clean up log data ten thousand record ago +joblog_clean_type_7=Clean up log data thirty thousand record ago +joblog_clean_type_8=Clean up log data hundred thousand record ago +joblog_clean_type_9=Clean up all log data +joblog_clean_type_unvalid=Clean type is illegal +joblog_handleCode_200=Success +joblog_handleCode_500=Fail +joblog_handleCode_502=Timeout +joblog_kill_log=Kill Job +joblog_kill_log_limit=Trigger Fail, can not kill job +joblog_kill_log_byman=Manual operation, kill job +joblog_lost_fail=Job result lost, marked as failure +joblog_rolling_log=Rolling log +joblog_rolling_log_refresh=Refresh +joblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log +joblog_rolling_log_failoften=The request for the Rolling log is terminated, the number of failed requests exceeds the limit, Reload the log on the refresh page +joblog_logid_unvalid=Log ID is illegal + +## job group +jobgroup_name=Executor Manage +jobgroup_list=Executor List +jobgroup_add=Add Executor +jobgroup_edit=Edit Executor +jobgroup_del=Delete Executor +jobgroup_field_title=Title +jobgroup_field_addressType=Registry Type +jobgroup_field_addressType_0=Automatic registration +jobgroup_field_addressType_1=Manual registration +jobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty +jobgroup_field_registryList=machine address +jobgroup_field_registryList_unvalid=registry machine address is illegal +jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated +jobgroup_field_appname_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and hyphen. +jobgroup_field_appname_length=AppName length is limited to 4~64 +jobgroup_field_title_length=Title length is limited to 4~12 +jobgroup_field_order_digits=Please enter a positive integer +jobgroup_field_orderrange=Order is limited to 1~1000 +jobgroup_del_limit_0=Refuse to delete, the executor is being used +jobgroup_del_limit_1=Refuses to delete, the system retains at least one executor +jobgroup_empty=There is no valid executor. Please contact the administrator + +## job conf +jobconf_block_SERIAL_EXECUTION=Serial execution +jobconf_block_DISCARD_LATER=Discard Later +jobconf_block_COVER_EARLY=Cover Early +jobconf_route_first=First +jobconf_route_last=Last +jobconf_route_round=Round +jobconf_route_random=Random +jobconf_route_consistenthash=Consistent Hash +jobconf_route_lfu=Least Frequently Used +jobconf_route_lru=Least Recently Used +jobconf_route_failover=Failover +jobconf_route_busyover=Busyover +jobconf_route_shard=Sharding Broadcast +jobconf_idleBeat=Idle check +jobconf_beat=Heartbeats +jobconf_monitor=Task Scheduling Center monitor alarm +jobconf_monitor_detail=monitor alarm details +jobconf_monitor_alarm_title=Alarm Type +jobconf_monitor_alarm_type=Trigger Fail +jobconf_monitor_alarm_content=Alarm Content +jobconf_trigger_admin_adress=Trigger machine address +jobconf_trigger_exe_regtype=Execotor-Registry Type +jobconf_trigger_exe_regaddress=Execotor-Registry Address +jobconf_trigger_address_empty=Trigger Fail:registry address is empty +jobconf_trigger_run=Trigger Job +jobconf_trigger_child_run=Trigger child job +jobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4}
+jobconf_callback_child_msg2={0}/{1} [Job ID={2}], Trigger Fail, Trigger msg: Job ID is illegal
+jobconf_trigger_type=Job trigger type +jobconf_trigger_type_cron=Cron trigger +jobconf_trigger_type_manual=Manual trigger +jobconf_trigger_type_parent=Parent job trigger +jobconf_trigger_type_api=Api trigger +jobconf_trigger_type_retry=Fail retry trigger +jobconf_trigger_type_misfire=Misfire compensation trigger + +## user +user_manage=User Manage +user_username=Username +user_password=Password +user_role=Role +user_role_admin=Admin User +user_role_normal=Normal User +user_permission=Permission +user_add=Add User +user_update=Edit User +user_username_repeat=Username Repeat +user_username_valid=Restrictions start with a lowercase letter and consist of lowercase letters and Numbers +user_password_update_placeholder=Please input password, empty means not update +user_update_loginuser_limit=Operation of current login account is not allowed + +## help +job_help=Tutorial +job_help_document=Official Document diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties b/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties new file mode 100644 index 0000000..b3860e4 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_zh_CN.properties @@ -0,0 +1,276 @@ +admin_name=任务调度中心 +admin_name_full=分布式任务调度平台XXL-JOB +admin_version=2.3.1 +admin_i18n= + +## system +system_tips=系统提示 +system_ok=确定 +system_close=关闭 +system_save=保存 +system_cancel=取消 +system_search=搜索 +system_status=状态 +system_opt=操作 +system_please_input=请输入 +system_please_choose=请选择 +system_success=成功 +system_fail=失败 +system_add_suc=新增成功 +system_add_fail=新增失败 +system_update_suc=更新成功 +system_update_fail=更新失败 +system_all=全部 +system_api_error=接口异常 +system_show=查看 +system_empty=无 +system_opt_suc=操作成功 +system_opt_fail=操作失败 +system_opt_edit=编辑 +system_opt_del=删除 +system_opt_copy=复制 +system_unvalid=非法 +system_not_found=不存在 +system_nav=导航 +system_digits=整数 +system_lengh_limit=长度限制 +system_permission_limit=权限拦截 +system_welcome=欢迎 + +## daterangepicker +daterangepicker_ranges_recent_hour=最近一小时 +daterangepicker_ranges_today=今日 +daterangepicker_ranges_yesterday=昨日 +daterangepicker_ranges_this_month=本月 +daterangepicker_ranges_last_month=上个月 +daterangepicker_ranges_recent_week=最近一周 +daterangepicker_ranges_recent_month=最近一月 +daterangepicker_custom_name=自定义 +daterangepicker_custom_starttime=起始时间 +daterangepicker_custom_endtime=结束时间 +daterangepicker_custom_daysofweek=日,一,二,三,四,五,六 +daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月 + +## dataTable +dataTable_sProcessing=处理中... +dataTable_sLengthMenu=每页 _MENU_ 条记录 +dataTable_sZeroRecords=没有匹配结果 +dataTable_sInfo=第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 ) +dataTable_sInfoEmpty=无记录 +dataTable_sInfoFiltered=(由 _MAX_ 项结果过滤) +dataTable_sSearch=搜索 +dataTable_sEmptyTable=表中数据为空 +dataTable_sLoadingRecords=载入中... +dataTable_sFirst=首页 +dataTable_sPrevious=上页 +dataTable_sNext=下页 +dataTable_sLast=末页 +dataTable_sSortAscending=: 以升序排列此列 +dataTable_sSortDescending=: 以降序排列此列 + +## login +login_btn=登录 +login_remember_me=记住密码 +login_username_placeholder=请输入登录账号 +login_password_placeholder=请输入登录密码 +login_username_empty=请输入登录账号 +login_username_lt_4=登录账号不应低于4位 +login_password_empty=请输入登录密码 +login_password_lt_4=登录密码不应低于4位 +login_success=登录成功 +login_fail=登录失败 +login_param_empty=账号或密码为空 +login_param_unvalid=账号或密码错误 + +## logout +logout_btn=注销 +logout_confirm=确认注销登录? +logout_success=注销成功 +logout_fail=注销失败 + +## change pwd +change_pwd=修改密码 +change_pwd_suc_to_logout=修改密码成功,即将注销登陆 +change_pwd_field_newpwd=新密码 + +## dashboard +job_dashboard_name=运行报表 +job_dashboard_job_num=任务数量 +job_dashboard_job_num_tip=调度中心运行的任务数量 +job_dashboard_trigger_num=调度次数 +job_dashboard_trigger_num_tip=调度中心触发的调度次数 +job_dashboard_jobgroup_num=执行器数量 +job_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量 +job_dashboard_report=调度报表 +job_dashboard_report_loaddata_fail=调度报表数据加载异常 +job_dashboard_date_report=日期分布图 +job_dashboard_rate_report=成功比例图 + +## job info +jobinfo_name=任务管理 +jobinfo_job=任务 +jobinfo_field_add=新增 +jobinfo_field_update=更新任务 +jobinfo_field_id=任务ID +jobinfo_field_jobgroup=执行器 +jobinfo_field_jobdesc=任务描述 +jobinfo_field_gluetype=运行模式 +jobinfo_field_executorparam=任务参数 +jobinfo_field_author=负责人 +jobinfo_field_timeout=任务超时时间 +jobinfo_field_alarmemail=报警邮件 +jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔 +jobinfo_field_executorRouteStrategy=路由策略 +jobinfo_field_childJobId=子任务ID +jobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔 +jobinfo_field_executorBlockStrategy=阻塞处理策略 +jobinfo_field_executorFailRetryCount=失败重试次数 +jobinfo_field_executorFailRetryCount_placeholder=失败重试次数,大于零时生效 +jobinfo_script_location=脚本位置 +jobinfo_shard_index=分片序号 +jobinfo_shard_total=分片总数 +jobinfo_opt_stop=停止 +jobinfo_opt_start=启动 +jobinfo_opt_log=查询日志 +jobinfo_opt_run=执行一次 +jobinfo_opt_run_tips=请输入本次执行的机器地址,为空则从执行器获取 +jobinfo_opt_registryinfo=注册节点 +jobinfo_opt_next_time=下次执行时间 +jobinfo_glue_remark=源码备注 +jobinfo_glue_remark_limit=源码备注长度限制为4~100 +jobinfo_glue_rollback=版本回溯 +jobinfo_glue_jobid_unvalid=任务ID非法 +jobinfo_glue_gluetype_unvalid=该任务非GLUE模式 +jobinfo_field_executorTimeout_placeholder=任务超时时间,单位秒,大于零时生效 +schedule_type=调度类型 +schedule_type_none=无 +schedule_type_cron=CRON +schedule_type_fix_rate=固定速度 +schedule_type_fix_delay=固定延迟 +schedule_type_none_limit_start=当前调度类型禁止启动 +misfire_strategy=调度过期策略 +misfire_strategy_do_nothing=忽略 +misfire_strategy_fire_once_now=立即执行一次 +jobinfo_conf_base=基础配置 +jobinfo_conf_schedule=调度配置 +jobinfo_conf_job=任务配置 +jobinfo_conf_advanced=高级配置 + +## job log +joblog_name=调度日志 +joblog_status=状态 +joblog_status_all=全部 +joblog_status_suc=成功 +joblog_status_fail=失败 +joblog_status_running=进行中 +joblog_field_triggerTime=调度时间 +joblog_field_triggerCode=调度结果 +joblog_field_triggerMsg=调度备注 +joblog_field_handleTime=执行时间 +joblog_field_handleCode=执行结果 +joblog_field_handleMsg=执行备注 +joblog_field_executorAddress=执行器地址 +joblog_clean=清理 +joblog_clean_log=日志清理 +joblog_clean_type=清理方式 +joblog_clean_type_1=清理一个月之前日志数据 +joblog_clean_type_2=清理三个月之前日志数据 +joblog_clean_type_3=清理六个月之前日志数据 +joblog_clean_type_4=清理一年之前日志数据 +joblog_clean_type_5=清理一千条以前日志数据 +joblog_clean_type_6=清理一万条以前日志数据 +joblog_clean_type_7=清理三万条以前日志数据 +joblog_clean_type_8=清理十万条以前日志数据 +joblog_clean_type_9=清理所有日志数据 +joblog_clean_type_unvalid=清理类型参数异常 +joblog_handleCode_200=成功 +joblog_handleCode_500=失败 +joblog_handleCode_502=失败(超时) +joblog_kill_log=终止任务 +joblog_kill_log_limit=调度失败,无法终止日志 +joblog_kill_log_byman=人为操作,主动终止 +joblog_lost_fail=任务结果丢失,标记失败 +joblog_rolling_log=执行日志 +joblog_rolling_log_refresh=刷新 +joblog_rolling_log_triggerfail=任务发起调度失败,无法查看执行日志 +joblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志 +joblog_logid_unvalid=日志ID非法 + +## job group +jobgroup_name=执行器管理 +jobgroup_list=执行器列表 +jobgroup_add=新增执行器 +jobgroup_edit=编辑执行器 +jobgroup_del=删除执行器 +jobgroup_field_title=名称 +jobgroup_field_addressType=注册方式 +jobgroup_field_addressType_0=自动注册 +jobgroup_field_addressType_1=手动录入 +jobgroup_field_addressType_limit=手动录入注册方式,机器地址不可为空 +jobgroup_field_registryList=机器地址 +jobgroup_field_registryList_unvalid=机器地址格式非法 +jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔 +jobgroup_field_appname_limit=限制以小写字母开头,由小写字母、数字和中划线组成 +jobgroup_field_appname_length=AppName长度限制为4~64 +jobgroup_field_title_length=名称长度限制为4~12 +jobgroup_field_order_digits=请输入整数 +jobgroup_field_orderrange=取值范围为1~1000 +jobgroup_del_limit_0=拒绝删除,该执行器使用中 +jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器 +jobgroup_empty=不存在有效执行器,请联系管理员 + +## job conf +jobconf_block_SERIAL_EXECUTION=单机串行 +jobconf_block_DISCARD_LATER=丢弃后续调度 +jobconf_block_COVER_EARLY=覆盖之前调度 +jobconf_route_first=第一个 +jobconf_route_last=最后一个 +jobconf_route_round=轮询 +jobconf_route_random=随机 +jobconf_route_consistenthash=一致性HASH +jobconf_route_lfu=最不经常使用 +jobconf_route_lru=最近最久未使用 +jobconf_route_failover=故障转移 +jobconf_route_busyover=忙碌转移 +jobconf_route_shard=分片广播 +jobconf_idleBeat=空闲检测 +jobconf_beat=心跳检测 +jobconf_monitor=任务调度中心监控报警 +jobconf_monitor_detail=监控告警明细 +jobconf_monitor_alarm_title=告警类型 +jobconf_monitor_alarm_type=调度失败 +jobconf_monitor_alarm_content=告警内容 +jobconf_trigger_admin_adress=调度机器 +jobconf_trigger_exe_regtype=执行器-注册方式 +jobconf_trigger_exe_regaddress=执行器-地址列表 +jobconf_trigger_address_empty=调度失败:执行器地址为空 +jobconf_trigger_run=触发调度 +jobconf_trigger_child_run=触发子任务 +jobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4}
+jobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误
+jobconf_trigger_type=任务触发类型 +jobconf_trigger_type_cron=Cron触发 +jobconf_trigger_type_manual=手动触发 +jobconf_trigger_type_parent=父任务触发 +jobconf_trigger_type_api=API触发 +jobconf_trigger_type_retry=失败重试触发 +jobconf_trigger_type_misfire=调度过期补偿 + +## user +user_manage=用户管理 +user_username=账号 +user_password=密码 +user_role=角色 +user_role_admin=管理员 +user_role_normal=普通用户 +user_permission=权限 +user_add=新增用户 +user_update=更新用户 +user_username_repeat=账号重复 +user_username_valid=限制以小写字母开头,由小写字母、数字组成 +user_password_update_placeholder=请输入新密码,为空则不更新密码 +user_update_loginuser_limit=禁止操作当前登录账号 + +## help +job_help=使用教程 +job_help_document=官方文档 diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties b/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties new file mode 100644 index 0000000..ca069b3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/i18n/message_zh_TC.properties @@ -0,0 +1,276 @@ +admin_name=任務調度中心 +admin_name_full=分布式任務調度平臺XXL-JOB +admin_version=2.3.1 +admin_i18n= + +## system +system_tips=系統提示 +system_ok=確定 +system_close=關閉 +system_save=儲存 +system_cancel=取消 +system_search=搜尋 +system_status=狀態 +system_opt=操作 +system_please_input=請輸入 +system_please_choose=请選擇 +system_success=成功 +system_fail=失敗 +system_add_suc=新增成功 +system_add_fail=新增失敗 +system_update_suc=更新成功 +system_update_fail=更新失敗 +system_all=全部 +system_api_error=API錯誤 +system_show=查看 +system_empty=無 +system_opt_suc=操作成功 +system_opt_fail=操作失敗 +system_opt_edit=編輯 +system_opt_del=刪除 +system_opt_copy=復制 +system_unvalid=非法 +system_not_found=不存在 +system_nav=導航 +system_digits=整數 +system_lengh_limit=長度限制 +system_permission_limit=權限控管 +system_welcome=歡迎 + +## daterangepicker +daterangepicker_ranges_recent_hour=最近一小時 +daterangepicker_ranges_today=今日 +daterangepicker_ranges_yesterday=昨日 +daterangepicker_ranges_this_month=本月 +daterangepicker_ranges_last_month=上個月 +daterangepicker_ranges_recent_week=最近一周 +daterangepicker_ranges_recent_month=最近一月 +daterangepicker_custom_name=自定義 +daterangepicker_custom_starttime=起始時間 +daterangepicker_custom_endtime=結束時間 +daterangepicker_custom_daysofweek=日,一,二,三,四,五,六 +daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月 + +## dataTable +dataTable_sProcessing=處理中... +dataTable_sLengthMenu=每頁 _MENU_ 條記錄 +dataTable_sZeroRecords=沒有相符合記錄 +dataTable_sInfo=第 _PAGE_ 頁 ( 總共 _PAGES_ 頁,_TOTAL_ 條記錄 ) +dataTable_sInfoEmpty=無記錄 +dataTable_sInfoFiltered=(由 _MAX_ 項結果過濾) +dataTable_sSearch=搜尋 +dataTable_sEmptyTable=表中資料為空 +dataTable_sLoadingRecords=載入中... +dataTable_sFirst=首頁 +dataTable_sPrevious=上頁 +dataTable_sNext=下頁 +dataTable_sLast=末頁 +dataTable_sSortAscending=: 以升幂排序此列 +dataTable_sSortDescending=: 以降幂排序此列 + +## login +login_btn=登入 +login_remember_me=記住密碼 +login_username_placeholder=請輸入登入帳號 +login_password_placeholder=請輸入登入密碼 +login_username_empty=請輸入登入帳號 +login_username_lt_4=登入帳號不應低於4位數 +login_password_empty=請輸入登入密碼 +login_password_lt_4=登入密碼不應低於4位數 +login_success=登入成功 +login_fail=登入失敗 +login_param_empty=帳號或密碼為空值 +login_param_unvalid=帳號或密碼錯誤 + +## logout +logout_btn=登出 +logout_confirm=確認登出? +logout_success=登出成功 +logout_fail=登出失敗 + +## change pwd +change_pwd=修改密碼 +change_pwd_suc_to_logout=修改密碼成功,即將登出 +change_pwd_field_newpwd=新密碼 + +## dashboard +job_dashboard_name=運行報表 +job_dashboard_job_num=任務數量 +job_dashboard_job_num_tip=調度中心運行的任務數量 +job_dashboard_trigger_num=調度次數 +job_dashboard_trigger_num_tip=調度中心觸發的調度次數 +job_dashboard_jobgroup_num=執行器數量 +job_dashboard_jobgroup_num_tip=調度中心在線的執行器機器數量 +job_dashboard_report=調度報表 +job_dashboard_report_loaddata_fail=調度報表資料加載異常 +job_dashboard_date_report=日期分布圖 +job_dashboard_rate_report=成功比例圖 + +## job info +jobinfo_name=任務管理 +jobinfo_job=任務 +jobinfo_field_add=新增 +jobinfo_field_update=更新任務 +jobinfo_field_id=任務ID +jobinfo_field_jobgroup=執行器 +jobinfo_field_jobdesc=任務描述 +jobinfo_field_gluetype=運行模式 +jobinfo_field_executorparam=任務參數 +jobinfo_field_author=負責人 +jobinfo_field_timeout=任務超時秒數 +jobinfo_field_alarmemail=告警郵件 +jobinfo_field_alarmemail_placeholder=輸入多個告警郵件地址,請以逗號分隔 +jobinfo_field_executorRouteStrategy=路由策略 +jobinfo_field_childJobId=子任務ID +jobinfo_field_childJobId_placeholder=輸入子任務ID,如有多個請以逗號分隔 +jobinfo_field_executorBlockStrategy=阻塞處理策略 +jobinfo_field_executorFailRetryCount=失敗重試次數 +jobinfo_field_executorFailRetryCount_placeholder=失敗重試次數,大於零時生效 +jobinfo_script_location=腳本位置 +jobinfo_shard_index=分片序號 +jobinfo_shard_total=分片總數 +jobinfo_opt_stop=停止 +jobinfo_opt_start=啟動 +jobinfo_opt_log=查詢日誌 +jobinfo_opt_run=執行一次 +jobinfo_opt_run_tips=請輸入本次執行的機器地址,為空則從執行器獲取 +jobinfo_opt_registryinfo=注冊節點 +jobinfo_opt_next_time=下次執行時間 +jobinfo_glue_remark=源碼備註 +jobinfo_glue_remark_limit=源碼備註長度限制為4~100 +jobinfo_glue_rollback=版本回復 +jobinfo_glue_jobid_unvalid=任務ID非法 +jobinfo_glue_gluetype_unvalid=該任務非GLUE模式 +jobinfo_field_executorTimeout_placeholder=任務超時時間,單位秒,大於零時生效 +schedule_type=調度類型 +schedule_type_none=無 +schedule_type_cron=CRON +schedule_type_fix_rate=固定速度 +schedule_type_fix_delay=固定延遲 +schedule_type_none_limit_start=當前調度類型禁止啟動 +misfire_strategy=調度過期策略 +misfire_strategy_do_nothing=忽略 +misfire_strategy_fire_once_now=立即執行壹次 +jobinfo_conf_base=基礎配置 +jobinfo_conf_schedule=調度配置 +jobinfo_conf_job=任務配置 +jobinfo_conf_advanced=高級配置 + +## job log +joblog_name=調度日誌 +joblog_status=狀態 +joblog_status_all=全部 +joblog_status_suc=成功 +joblog_status_fail=失敗 +joblog_status_running=進行中 +joblog_field_triggerTime=調度時間 +joblog_field_triggerCode=調度結果 +joblog_field_triggerMsg=調度備註 +joblog_field_handleTime=執行時間 +joblog_field_handleCode=執行结果 +joblog_field_handleMsg=執行備註 +joblog_field_executorAddress=執行器地址 +joblog_clean=清理 +joblog_clean_log=日誌清理 +joblog_clean_type=清理方式 +joblog_clean_type_1=清理一個月之前日誌資料 +joblog_clean_type_2=清理三個月之前日誌資料 +joblog_clean_type_3=清理六個月之前日誌資料 +joblog_clean_type_4=清理一年之前日誌資料 +joblog_clean_type_5=清理一千條以前日誌資料 +joblog_clean_type_6=清理一萬條以前日誌資料 +joblog_clean_type_7=清理三萬條以前日誌資料 +joblog_clean_type_8=清理十萬條以前日誌資料 +joblog_clean_type_9=清理所有日誌資料 +joblog_clean_type_unvalid=清理類型參数異常 +joblog_handleCode_200=成功 +joblog_handleCode_500=失敗 +joblog_handleCode_502=失敗(超時) +joblog_kill_log=终止任務 +joblog_kill_log_limit=調度失敗,無法终止日誌 +joblog_kill_log_byman=人為操作,主動終止 +joblog_lost_fail=任務結果丟失,標記失敗 +joblog_rolling_log=執行日誌 +joblog_rolling_log_refresh=更新 +joblog_rolling_log_triggerfail=任務發起調度失敗,無法查看執行日誌 +joblog_rolling_log_failoften=終止請求Rolling日誌,請求失敗次數超上限,可刷新頁面重新加載日誌 +joblog_logid_unvalid=日誌ID非法 + +## job group +jobgroup_name=執行器管理 +jobgroup_list=執行器列表 +jobgroup_add=新增執行器 +jobgroup_edit=編輯執行器 +jobgroup_del=刪除執行器 +jobgroup_field_title=名稱 +jobgroup_field_addressType=注冊方式 +jobgroup_field_addressType_0=自動注冊 +jobgroup_field_addressType_1=手動登錄 +jobgroup_field_addressType_limit=手動登錄注冊方式,機器地址不可為空 +jobgroup_field_registryList=機器地址 +jobgroup_field_registryList_unvalid=機器地址格式非法 +jobgroup_field_registryList_placeholder=請輸入執行器地址列表,多個地址請以逗號分隔 +jobgroup_field_appname_limit=限制以小寫字母開頭,由小寫字母、數字和中划線組成 +jobgroup_field_appname_length=AppName長度限制為4~64 +jobgroup_field_title_length=名稱長度限制為4~12 +jobgroup_field_order_digits=請輸入整數 +jobgroup_field_orderrange=取值範圍為1~1000 +jobgroup_del_limit_0=拒絕刪除,該執行器使用中 +jobgroup_del_limit_1=拒絕删除,系统至少保留一個執行器 +jobgroup_empty=不存在有效執行器,請聯絡系統管理員 + +## job conf +jobconf_block_SERIAL_EXECUTION=單機串行 +jobconf_block_DISCARD_LATER=丢棄后續調度 +jobconf_block_COVER_EARLY=覆蓋之前調度 +jobconf_route_first=第一個 +jobconf_route_last=最後一個 +jobconf_route_round=輪詢 +jobconf_route_random=隨機 +jobconf_route_consistenthash=一致性HASH +jobconf_route_lfu=最不經常使用 +jobconf_route_lru=最近最久未使用 +jobconf_route_failover=故障轉移 +jobconf_route_busyover=忙碌轉移 +jobconf_route_shard=分片廣播 +jobconf_idleBeat=空閒檢測 +jobconf_beat=心跳檢測 +jobconf_monitor=任務調度中心監控告警 +jobconf_monitor_detail=監控告警明细 +jobconf_monitor_alarm_title=告警類型 +jobconf_monitor_alarm_type=調度失敗 +jobconf_monitor_alarm_content=告警内容 +jobconf_trigger_admin_adress=調度機器 +jobconf_trigger_exe_regtype=執行器-注冊方式 +jobconf_trigger_exe_regaddress=執行器-地址列表 +jobconf_trigger_address_empty=調度失敗:執行器地址為空 +jobconf_trigger_run=觸發調度 +jobconf_trigger_child_run=觸發子任務 +jobconf_callback_child_msg1={0}/{1} [任務ID={2}], 觸發{3}, 觸發備註: {4}
+jobconf_callback_child_msg2={0}/{1} [任務ID={2}], 觸發失败, 觸發備註: 任務ID格式錯誤
+jobconf_trigger_type=任務觸發類型 +jobconf_trigger_type_cron=Cron觸發 +jobconf_trigger_type_manual=手動觸發 +jobconf_trigger_type_parent=父任務觸發 +jobconf_trigger_type_api=API觸發 +jobconf_trigger_type_retry=失敗重試觸發 +jobconf_trigger_type_misfire=調度過期補償 + +## user +user_manage=用户管理 +user_username=帳號 +user_password=密碼 +user_role=角色 +user_role_admin=管理員 +user_role_normal=普通用戶 +user_permission=權限 +user_add=新增用戶 +user_update=更新用戶 +user_username_repeat=帳號重複 +user_username_valid=限制以小寫字母開頭,由小寫字母、數字組成 +user_password_update_placeholder=請輸入新密碼,為空則不更新密碼 +user_update_loginuser_limit=禁止操作當前登入帳號 + +## help +job_help=使用教程 +job_help_document=官方文件 diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/logback.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/logback.xml new file mode 100644 index 0000000..a30b99b --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/logback.xml @@ -0,0 +1,34 @@ + + + + logback + + + + + + + ${console.log.pattern} + utf-8 + + + + + ${log.path}.log + + ${log.path}.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml new file mode 100644 index 0000000..ee592bb --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobGroupMapper.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + t.id, + t.app_name, + t.title, + t.address_type, + t.address_list, + t.update_time + + + + + + + + INSERT INTO xxl_job_group ( `app_name`, `title`, `address_type`, `address_list`, `update_time`) + values ( #{appname}, #{title}, #{addressType}, #{addressList}, #{updateTime} ); + + + + UPDATE xxl_job_group + SET `app_name` = #{appname}, + `title` = #{title}, + `address_type` = #{addressType}, + `address_list` = #{addressList}, + `update_time` = #{updateTime} + WHERE id = #{id} + + + + DELETE FROM xxl_job_group + WHERE id = #{id} + + + + + + + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml new file mode 100644 index 0000000..c40b059 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + t.id, + t.job_group, + t.job_desc, + t.add_time, + t.update_time, + t.author, + t.alarm_email, + t.schedule_type, + t.schedule_conf, + t.misfire_strategy, + t.executor_route_strategy, + t.executor_handler, + t.executor_param, + t.executor_block_strategy, + t.executor_timeout, + t.executor_fail_retry_count, + t.glue_type, + t.glue_source, + t.glue_remark, + t.glue_updatetime, + t.child_jobid, + t.trigger_status, + t.trigger_last_time, + t.trigger_next_time + + + + + + + + INSERT INTO xxl_job_info ( + job_group, + job_desc, + add_time, + update_time, + author, + alarm_email, + schedule_type, + schedule_conf, + misfire_strategy, + executor_route_strategy, + executor_handler, + executor_param, + executor_block_strategy, + executor_timeout, + executor_fail_retry_count, + glue_type, + glue_source, + glue_remark, + glue_updatetime, + child_jobid, + trigger_status, + trigger_last_time, + trigger_next_time + ) VALUES ( + #{jobGroup}, + #{jobDesc}, + #{addTime}, + #{updateTime}, + #{author}, + #{alarmEmail}, + #{scheduleType}, + #{scheduleConf}, + #{misfireStrategy}, + #{executorRouteStrategy}, + #{executorHandler}, + #{executorParam}, + #{executorBlockStrategy}, + #{executorTimeout}, + #{executorFailRetryCount}, + #{glueType}, + #{glueSource}, + #{glueRemark}, + #{glueUpdatetime}, + #{childJobId}, + #{triggerStatus}, + #{triggerLastTime}, + #{triggerNextTime} + ); + + + + + + + UPDATE xxl_job_info + SET + job_group = #{jobGroup}, + job_desc = #{jobDesc}, + update_time = #{updateTime}, + author = #{author}, + alarm_email = #{alarmEmail}, + schedule_type = #{scheduleType}, + schedule_conf = #{scheduleConf}, + misfire_strategy = #{misfireStrategy}, + executor_route_strategy = #{executorRouteStrategy}, + executor_handler = #{executorHandler}, + executor_param = #{executorParam}, + executor_block_strategy = #{executorBlockStrategy}, + executor_timeout = ${executorTimeout}, + executor_fail_retry_count = ${executorFailRetryCount}, + glue_type = #{glueType}, + glue_source = #{glueSource}, + glue_remark = #{glueRemark}, + glue_updatetime = #{glueUpdatetime}, + child_jobid = #{childJobId}, + trigger_status = #{triggerStatus}, + trigger_last_time = #{triggerLastTime}, + trigger_next_time = #{triggerNextTime} + WHERE id = #{id} + + + + DELETE + FROM xxl_job_info + WHERE id = #{id} + + + + + + + + + + + UPDATE xxl_job_info + SET + trigger_last_time = #{triggerLastTime}, + trigger_next_time = #{triggerNextTime}, + trigger_status = #{triggerStatus} + WHERE id = #{id} + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogGlueMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogGlueMapper.xml new file mode 100644 index 0000000..dc680f3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogGlueMapper.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + t.id, + t.job_id, + t.glue_type, + t.glue_source, + t.glue_remark, + t.add_time, + t.update_time + + + + INSERT INTO xxl_job_logglue ( + `job_id`, + `glue_type`, + `glue_source`, + `glue_remark`, + `add_time`, + `update_time` + ) VALUES ( + #{jobId}, + #{glueType}, + #{glueSource}, + #{glueRemark}, + #{addTime}, + #{updateTime} + ); + + + + + + + DELETE FROM xxl_job_logglue + WHERE id NOT in( + SELECT id FROM( + SELECT id FROM xxl_job_logglue + WHERE `job_id` = #{jobId} + ORDER BY update_time desc + LIMIT 0, #{limit} + ) t1 + ) AND `job_id` = #{jobId} + + + + DELETE FROM xxl_job_logglue + WHERE `job_id` = #{jobId} + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml new file mode 100644 index 0000000..e5fa903 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + t.id, + t.job_group, + t.job_id, + t.executor_address, + t.executor_handler, + t.executor_param, + t.executor_sharding_param, + t.executor_fail_retry_count, + t.trigger_time, + t.trigger_code, + t.trigger_msg, + t.handle_time, + t.handle_code, + t.handle_msg, + t.alarm_status + + + + + + + + + + + INSERT INTO xxl_job_log ( + `job_group`, + `job_id`, + `trigger_time`, + `trigger_code`, + `handle_code` + ) VALUES ( + #{jobGroup}, + #{jobId}, + #{triggerTime}, + #{triggerCode}, + #{handleCode} + ); + + + + + UPDATE xxl_job_log + SET + `trigger_time`= #{triggerTime}, + `trigger_code`= #{triggerCode}, + `trigger_msg`= #{triggerMsg}, + `executor_address`= #{executorAddress}, + `executor_handler`=#{executorHandler}, + `executor_param`= #{executorParam}, + `executor_sharding_param`= #{executorShardingParam}, + `executor_fail_retry_count`= #{executorFailRetryCount} + WHERE `id`= #{id} + + + + UPDATE xxl_job_log + SET + `handle_time`= #{handleTime}, + `handle_code`= #{handleCode}, + `handle_msg`= #{handleMsg} + WHERE `id`= #{id} + + + + delete from xxl_job_log + WHERE job_id = #{jobId} + + + + + + + + + + delete from xxl_job_log + WHERE id in + + #{item} + + + + + + + UPDATE xxl_job_log + SET + `alarm_status` = #{newAlarmStatus} + WHERE `id`= #{logId} AND `alarm_status` = #{oldAlarmStatus} + + + + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogReportMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogReportMapper.xml new file mode 100644 index 0000000..a993a5b --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogReportMapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + t.id, + t.trigger_day, + t.running_count, + t.suc_count, + t.fail_count + + + + INSERT INTO xxl_job_log_report ( + `trigger_day`, + `running_count`, + `suc_count`, + `fail_count` + ) VALUES ( + #{triggerDay}, + #{runningCount}, + #{sucCount}, + #{failCount} + ); + + + + + UPDATE xxl_job_log_report + SET `running_count` = #{runningCount}, + `suc_count` = #{sucCount}, + `fail_count` = #{failCount} + WHERE `trigger_day` = #{triggerDay} + + + + + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobRegistryMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobRegistryMapper.xml new file mode 100644 index 0000000..690841f --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobRegistryMapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + t.id, + t.registry_group, + t.registry_key, + t.registry_value, + t.update_time + + + + + + DELETE FROM xxl_job_registry + WHERE id in + + #{item} + + + + + + + UPDATE xxl_job_registry + SET `update_time` = #{updateTime} + WHERE `registry_group` = #{registryGroup} + AND `registry_key` = #{registryKey} + AND `registry_value` = #{registryValue} + + + + INSERT INTO xxl_job_registry( `registry_group` , `registry_key` , `registry_value`, `update_time`) + VALUES( #{registryGroup} , #{registryKey} , #{registryValue}, #{updateTime}) + + + + DELETE FROM xxl_job_registry + WHERE registry_group = #{registryGroup} + AND registry_key = #{registryKey} + AND registry_value = #{registryValue} + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobUserMapper.xml b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobUserMapper.xml new file mode 100644 index 0000000..334d2c5 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobUserMapper.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + t.id, + t.username, + t.password, + t.role, + t.permission + + + + + + + + + + INSERT INTO xxl_job_user ( + username, + password, + role, + permission + ) VALUES ( + #{username}, + #{password}, + #{role}, + #{permission} + ); + + + + UPDATE xxl_job_user + SET + + password = #{password}, + + role = #{role}, + permission = #{permission} + WHERE id = #{id} + + + + DELETE + FROM xxl_job_user + WHERE id = #{id} + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/css/ionicons.min.css b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/css/ionicons.min.css new file mode 100644 index 0000000..baba9e9 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/css/ionicons.min.css @@ -0,0 +1,11 @@ +@charset "UTF-8";/*! + Ionicons, v2.0.0 + Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ + https://twitter.com/benjsperry https://twitter.com/ionicframework + MIT License: https://github.com/driftyco/ionicons + + Android-style icons originally built by Google’s + Material Design Icons: https://github.com/google/material-design-icons + used under CC BY http://creativecommons.org/licenses/by/4.0/ + Modified icons to fit ionicon’s grid from original. +*/@font-face{font-family:"Ionicons";src:url("../fonts/ionicons.eot?v=2.0.0");src:url("../fonts/ionicons.eot?v=2.0.0#iefix") format("embedded-opentype"),url("../fonts/ionicons.ttf?v=2.0.0") format("truetype"),url("../fonts/ionicons.woff?v=2.0.0") format("woff"),url("../fonts/ionicons.svg?v=2.0.0#Ionicons") format("svg");font-weight:normal;font-style:normal}.ion,.ionicons,.ion-alert:before,.ion-alert-circled:before,.ion-android-add:before,.ion-android-add-circle:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done:before,.ion-android-done-all:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite:before,.ion-android-favorite-outline:before,.ion-android-film:before,.ion-android-folder:before,.ion-android-folder-open:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone:before,.ion-android-microphone-off:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person:before,.ion-android-person-add:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove:before,.ion-android-remove-circle:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share:before,.ion-android-share-alt:before,.ion-android-star:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace:before,.ion-backspace-outline:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox:before,.ion-chatbox-working:before,.ion-chatboxes:before,.ion-chatbubble:before,.ion-chatbubble-working:before,.ion-chatbubbles:before,.ion-checkmark:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close:before,.ion-close-circled:before,.ion-close-round:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code:before,.ion-code-download:before,.ion-code-working:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document:before,.ion-document-text:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email:before,.ion-email-unread:before,.ion-erlenmeyer-flask:before,.ion-erlenmeyer-flask-bubbles:before,.ion-eye:before,.ion-eye-disabled:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash:before,.ion-flash-off:before,.ion-folder:before,.ion-fork:before,.ion-fork-repo:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy:before,.ion-happy-outline:before,.ion-headphone:before,.ion-heart:before,.ion-heart-broken:before,.ion-help:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information:before,.ion-information-circled:before,.ion-ionic:before,.ion-ios-alarm:before,.ion-ios-alarm-outline:before,.ion-ios-albums:before,.ion-ios-albums-outline:before,.ion-ios-americanfootball:before,.ion-ios-americanfootball-outline:before,.ion-ios-analytics:before,.ion-ios-analytics-outline:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at:before,.ion-ios-at-outline:before,.ion-ios-barcode:before,.ion-ios-barcode-outline:before,.ion-ios-baseball:before,.ion-ios-baseball-outline:before,.ion-ios-basketball:before,.ion-ios-basketball-outline:before,.ion-ios-bell:before,.ion-ios-bell-outline:before,.ion-ios-body:before,.ion-ios-body-outline:before,.ion-ios-bolt:before,.ion-ios-bolt-outline:before,.ion-ios-book:before,.ion-ios-book-outline:before,.ion-ios-bookmarks:before,.ion-ios-bookmarks-outline:before,.ion-ios-box:before,.ion-ios-box-outline:before,.ion-ios-briefcase:before,.ion-ios-briefcase-outline:before,.ion-ios-browsers:before,.ion-ios-browsers-outline:before,.ion-ios-calculator:before,.ion-ios-calculator-outline:before,.ion-ios-calendar:before,.ion-ios-calendar-outline:before,.ion-ios-camera:before,.ion-ios-camera-outline:before,.ion-ios-cart:before,.ion-ios-cart-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatbubble:before,.ion-ios-chatbubble-outline:before,.ion-ios-checkmark:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock:before,.ion-ios-clock-outline:before,.ion-ios-close:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-cloud:before,.ion-ios-cloud-download:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloudy:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-outline:before,.ion-ios-cog:before,.ion-ios-cog-outline:before,.ion-ios-color-filter:before,.ion-ios-color-filter-outline:before,.ion-ios-color-wand:before,.ion-ios-color-wand-outline:before,.ion-ios-compose:before,.ion-ios-compose-outline:before,.ion-ios-contact:before,.ion-ios-contact-outline:before,.ion-ios-copy:before,.ion-ios-copy-outline:before,.ion-ios-crop:before,.ion-ios-crop-strong:before,.ion-ios-download:before,.ion-ios-download-outline:before,.ion-ios-drag:before,.ion-ios-email:before,.ion-ios-email-outline:before,.ion-ios-eye:before,.ion-ios-eye-outline:before,.ion-ios-fastforward:before,.ion-ios-fastforward-outline:before,.ion-ios-filing:before,.ion-ios-filing-outline:before,.ion-ios-film:before,.ion-ios-film-outline:before,.ion-ios-flag:before,.ion-ios-flag-outline:before,.ion-ios-flame:before,.ion-ios-flame-outline:before,.ion-ios-flask:before,.ion-ios-flask-outline:before,.ion-ios-flower:before,.ion-ios-flower-outline:before,.ion-ios-folder:before,.ion-ios-folder-outline:before,.ion-ios-football:before,.ion-ios-football-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-b:before,.ion-ios-game-controller-b-outline:before,.ion-ios-gear:before,.ion-ios-gear-outline:before,.ion-ios-glasses:before,.ion-ios-glasses-outline:before,.ion-ios-grid-view:before,.ion-ios-grid-view-outline:before,.ion-ios-heart:before,.ion-ios-heart-outline:before,.ion-ios-help:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-home:before,.ion-ios-home-outline:before,.ion-ios-infinite:before,.ion-ios-infinite-outline:before,.ion-ios-information:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-ionic-outline:before,.ion-ios-keypad:before,.ion-ios-keypad-outline:before,.ion-ios-lightbulb:before,.ion-ios-lightbulb-outline:before,.ion-ios-list:before,.ion-ios-list-outline:before,.ion-ios-location:before,.ion-ios-location-outline:before,.ion-ios-locked:before,.ion-ios-locked-outline:before,.ion-ios-loop:before,.ion-ios-loop-strong:before,.ion-ios-medical:before,.ion-ios-medical-outline:before,.ion-ios-medkit:before,.ion-ios-medkit-outline:before,.ion-ios-mic:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-minus:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-monitor:before,.ion-ios-monitor-outline:before,.ion-ios-moon:before,.ion-ios-moon-outline:before,.ion-ios-more:before,.ion-ios-more-outline:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate:before,.ion-ios-navigate-outline:before,.ion-ios-nutrition:before,.ion-ios-nutrition-outline:before,.ion-ios-paper:before,.ion-ios-paper-outline:before,.ion-ios-paperplane:before,.ion-ios-paperplane-outline:before,.ion-ios-partlysunny:before,.ion-ios-partlysunny-outline:before,.ion-ios-pause:before,.ion-ios-pause-outline:before,.ion-ios-paw:before,.ion-ios-paw-outline:before,.ion-ios-people:before,.ion-ios-people-outline:before,.ion-ios-person:before,.ion-ios-person-outline:before,.ion-ios-personadd:before,.ion-ios-personadd-outline:before,.ion-ios-photos:before,.ion-ios-photos-outline:before,.ion-ios-pie:before,.ion-ios-pie-outline:before,.ion-ios-pint:before,.ion-ios-pint-outline:before,.ion-ios-play:before,.ion-ios-play-outline:before,.ion-ios-plus:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetags:before,.ion-ios-pricetags-outline:before,.ion-ios-printer:before,.ion-ios-printer-outline:before,.ion-ios-pulse:before,.ion-ios-pulse-strong:before,.ion-ios-rainy:before,.ion-ios-rainy-outline:before,.ion-ios-recording:before,.ion-ios-recording-outline:before,.ion-ios-redo:before,.ion-ios-redo-outline:before,.ion-ios-refresh:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-reload:before,.ion-ios-reverse-camera:before,.ion-ios-reverse-camera-outline:before,.ion-ios-rewind:before,.ion-ios-rewind-outline:before,.ion-ios-rose:before,.ion-ios-rose-outline:before,.ion-ios-search:before,.ion-ios-search-strong:before,.ion-ios-settings:before,.ion-ios-settings-strong:before,.ion-ios-shuffle:before,.ion-ios-shuffle-strong:before,.ion-ios-skipbackward:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipforward:before,.ion-ios-skipforward-outline:before,.ion-ios-snowy:before,.ion-ios-speedometer:before,.ion-ios-speedometer-outline:before,.ion-ios-star:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-stopwatch:before,.ion-ios-stopwatch-outline:before,.ion-ios-sunny:before,.ion-ios-sunny-outline:before,.ion-ios-telephone:before,.ion-ios-telephone-outline:before,.ion-ios-tennisball:before,.ion-ios-tennisball-outline:before,.ion-ios-thunderstorm:before,.ion-ios-thunderstorm-outline:before,.ion-ios-time:before,.ion-ios-time-outline:before,.ion-ios-timer:before,.ion-ios-timer-outline:before,.ion-ios-toggle:before,.ion-ios-toggle-outline:before,.ion-ios-trash:before,.ion-ios-trash-outline:before,.ion-ios-undo:before,.ion-ios-undo-outline:before,.ion-ios-unlocked:before,.ion-ios-unlocked-outline:before,.ion-ios-upload:before,.ion-ios-upload-outline:before,.ion-ios-videocam:before,.ion-ios-videocam-outline:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass:before,.ion-ios-wineglass-outline:before,.ion-ios-world:before,.ion-ios-world-outline:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon:before,.ion-navicon-round:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person:before,.ion-person-add:before,.ion-person-stalker:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply:before,.ion-reply-all:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad:before,.ion-sad-outline:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android:before,.ion-social-android-outline:before,.ion-social-angular:before,.ion-social-angular-outline:before,.ion-social-apple:before,.ion-social-apple-outline:before,.ion-social-bitcoin:before,.ion-social-bitcoin-outline:before,.ion-social-buffer:before,.ion-social-buffer-outline:before,.ion-social-chrome:before,.ion-social-chrome-outline:before,.ion-social-codepen:before,.ion-social-codepen-outline:before,.ion-social-css3:before,.ion-social-css3-outline:before,.ion-social-designernews:before,.ion-social-designernews-outline:before,.ion-social-dribbble:before,.ion-social-dribbble-outline:before,.ion-social-dropbox:before,.ion-social-dropbox-outline:before,.ion-social-euro:before,.ion-social-euro-outline:before,.ion-social-facebook:before,.ion-social-facebook-outline:before,.ion-social-foursquare:before,.ion-social-foursquare-outline:before,.ion-social-freebsd-devil:before,.ion-social-github:before,.ion-social-github-outline:before,.ion-social-google:before,.ion-social-google-outline:before,.ion-social-googleplus:before,.ion-social-googleplus-outline:before,.ion-social-hackernews:before,.ion-social-hackernews-outline:before,.ion-social-html5:before,.ion-social-html5-outline:before,.ion-social-instagram:before,.ion-social-instagram-outline:before,.ion-social-javascript:before,.ion-social-javascript-outline:before,.ion-social-linkedin:before,.ion-social-linkedin-outline:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest:before,.ion-social-pinterest-outline:before,.ion-social-python:before,.ion-social-reddit:before,.ion-social-reddit-outline:before,.ion-social-rss:before,.ion-social-rss-outline:before,.ion-social-sass:before,.ion-social-skype:before,.ion-social-skype-outline:before,.ion-social-snapchat:before,.ion-social-snapchat-outline:before,.ion-social-tumblr:before,.ion-social-tumblr-outline:before,.ion-social-tux:before,.ion-social-twitch:before,.ion-social-twitch-outline:before,.ion-social-twitter:before,.ion-social-twitter-outline:before,.ion-social-usd:before,.ion-social-usd-outline:before,.ion-social-vimeo:before,.ion-social-vimeo-outline:before,.ion-social-whatsapp:before,.ion-social-whatsapp-outline:before,.ion-social-windows:before,.ion-social-windows-outline:before,.ion-social-wordpress:before,.ion-social-wordpress-outline:before,.ion-social-yahoo:before,.ion-social-yahoo-outline:before,.ion-social-yen:before,.ion-social-yen-outline:before,.ion-social-youtube:before,.ion-social-youtube-outline:before,.ion-soup-can:before,.ion-soup-can-outline:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle:before,.ion-toggle-filled:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt:before,.ion-tshirt-outline:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before{display:inline-block;font-family:"Ionicons";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ion-alert:before{content:"\f101"}.ion-alert-circled:before{content:"\f100"}.ion-android-add:before{content:"\f2c7"}.ion-android-add-circle:before{content:"\f359"}.ion-android-alarm-clock:before{content:"\f35a"}.ion-android-alert:before{content:"\f35b"}.ion-android-apps:before{content:"\f35c"}.ion-android-archive:before{content:"\f2c9"}.ion-android-arrow-back:before{content:"\f2ca"}.ion-android-arrow-down:before{content:"\f35d"}.ion-android-arrow-dropdown:before{content:"\f35f"}.ion-android-arrow-dropdown-circle:before{content:"\f35e"}.ion-android-arrow-dropleft:before{content:"\f361"}.ion-android-arrow-dropleft-circle:before{content:"\f360"}.ion-android-arrow-dropright:before{content:"\f363"}.ion-android-arrow-dropright-circle:before{content:"\f362"}.ion-android-arrow-dropup:before{content:"\f365"}.ion-android-arrow-dropup-circle:before{content:"\f364"}.ion-android-arrow-forward:before{content:"\f30f"}.ion-android-arrow-up:before{content:"\f366"}.ion-android-attach:before{content:"\f367"}.ion-android-bar:before{content:"\f368"}.ion-android-bicycle:before{content:"\f369"}.ion-android-boat:before{content:"\f36a"}.ion-android-bookmark:before{content:"\f36b"}.ion-android-bulb:before{content:"\f36c"}.ion-android-bus:before{content:"\f36d"}.ion-android-calendar:before{content:"\f2d1"}.ion-android-call:before{content:"\f2d2"}.ion-android-camera:before{content:"\f2d3"}.ion-android-cancel:before{content:"\f36e"}.ion-android-car:before{content:"\f36f"}.ion-android-cart:before{content:"\f370"}.ion-android-chat:before{content:"\f2d4"}.ion-android-checkbox:before{content:"\f374"}.ion-android-checkbox-blank:before{content:"\f371"}.ion-android-checkbox-outline:before{content:"\f373"}.ion-android-checkbox-outline-blank:before{content:"\f372"}.ion-android-checkmark-circle:before{content:"\f375"}.ion-android-clipboard:before{content:"\f376"}.ion-android-close:before{content:"\f2d7"}.ion-android-cloud:before{content:"\f37a"}.ion-android-cloud-circle:before{content:"\f377"}.ion-android-cloud-done:before{content:"\f378"}.ion-android-cloud-outline:before{content:"\f379"}.ion-android-color-palette:before{content:"\f37b"}.ion-android-compass:before{content:"\f37c"}.ion-android-contact:before{content:"\f2d8"}.ion-android-contacts:before{content:"\f2d9"}.ion-android-contract:before{content:"\f37d"}.ion-android-create:before{content:"\f37e"}.ion-android-delete:before{content:"\f37f"}.ion-android-desktop:before{content:"\f380"}.ion-android-document:before{content:"\f381"}.ion-android-done:before{content:"\f383"}.ion-android-done-all:before{content:"\f382"}.ion-android-download:before{content:"\f2dd"}.ion-android-drafts:before{content:"\f384"}.ion-android-exit:before{content:"\f385"}.ion-android-expand:before{content:"\f386"}.ion-android-favorite:before{content:"\f388"}.ion-android-favorite-outline:before{content:"\f387"}.ion-android-film:before{content:"\f389"}.ion-android-folder:before{content:"\f2e0"}.ion-android-folder-open:before{content:"\f38a"}.ion-android-funnel:before{content:"\f38b"}.ion-android-globe:before{content:"\f38c"}.ion-android-hand:before{content:"\f2e3"}.ion-android-hangout:before{content:"\f38d"}.ion-android-happy:before{content:"\f38e"}.ion-android-home:before{content:"\f38f"}.ion-android-image:before{content:"\f2e4"}.ion-android-laptop:before{content:"\f390"}.ion-android-list:before{content:"\f391"}.ion-android-locate:before{content:"\f2e9"}.ion-android-lock:before{content:"\f392"}.ion-android-mail:before{content:"\f2eb"}.ion-android-map:before{content:"\f393"}.ion-android-menu:before{content:"\f394"}.ion-android-microphone:before{content:"\f2ec"}.ion-android-microphone-off:before{content:"\f395"}.ion-android-more-horizontal:before{content:"\f396"}.ion-android-more-vertical:before{content:"\f397"}.ion-android-navigate:before{content:"\f398"}.ion-android-notifications:before{content:"\f39b"}.ion-android-notifications-none:before{content:"\f399"}.ion-android-notifications-off:before{content:"\f39a"}.ion-android-open:before{content:"\f39c"}.ion-android-options:before{content:"\f39d"}.ion-android-people:before{content:"\f39e"}.ion-android-person:before{content:"\f3a0"}.ion-android-person-add:before{content:"\f39f"}.ion-android-phone-landscape:before{content:"\f3a1"}.ion-android-phone-portrait:before{content:"\f3a2"}.ion-android-pin:before{content:"\f3a3"}.ion-android-plane:before{content:"\f3a4"}.ion-android-playstore:before{content:"\f2f0"}.ion-android-print:before{content:"\f3a5"}.ion-android-radio-button-off:before{content:"\f3a6"}.ion-android-radio-button-on:before{content:"\f3a7"}.ion-android-refresh:before{content:"\f3a8"}.ion-android-remove:before{content:"\f2f4"}.ion-android-remove-circle:before{content:"\f3a9"}.ion-android-restaurant:before{content:"\f3aa"}.ion-android-sad:before{content:"\f3ab"}.ion-android-search:before{content:"\f2f5"}.ion-android-send:before{content:"\f2f6"}.ion-android-settings:before{content:"\f2f7"}.ion-android-share:before{content:"\f2f8"}.ion-android-share-alt:before{content:"\f3ac"}.ion-android-star:before{content:"\f2fc"}.ion-android-star-half:before{content:"\f3ad"}.ion-android-star-outline:before{content:"\f3ae"}.ion-android-stopwatch:before{content:"\f2fd"}.ion-android-subway:before{content:"\f3af"}.ion-android-sunny:before{content:"\f3b0"}.ion-android-sync:before{content:"\f3b1"}.ion-android-textsms:before{content:"\f3b2"}.ion-android-time:before{content:"\f3b3"}.ion-android-train:before{content:"\f3b4"}.ion-android-unlock:before{content:"\f3b5"}.ion-android-upload:before{content:"\f3b6"}.ion-android-volume-down:before{content:"\f3b7"}.ion-android-volume-mute:before{content:"\f3b8"}.ion-android-volume-off:before{content:"\f3b9"}.ion-android-volume-up:before{content:"\f3ba"}.ion-android-walk:before{content:"\f3bb"}.ion-android-warning:before{content:"\f3bc"}.ion-android-watch:before{content:"\f3bd"}.ion-android-wifi:before{content:"\f305"}.ion-aperture:before{content:"\f313"}.ion-archive:before{content:"\f102"}.ion-arrow-down-a:before{content:"\f103"}.ion-arrow-down-b:before{content:"\f104"}.ion-arrow-down-c:before{content:"\f105"}.ion-arrow-expand:before{content:"\f25e"}.ion-arrow-graph-down-left:before{content:"\f25f"}.ion-arrow-graph-down-right:before{content:"\f260"}.ion-arrow-graph-up-left:before{content:"\f261"}.ion-arrow-graph-up-right:before{content:"\f262"}.ion-arrow-left-a:before{content:"\f106"}.ion-arrow-left-b:before{content:"\f107"}.ion-arrow-left-c:before{content:"\f108"}.ion-arrow-move:before{content:"\f263"}.ion-arrow-resize:before{content:"\f264"}.ion-arrow-return-left:before{content:"\f265"}.ion-arrow-return-right:before{content:"\f266"}.ion-arrow-right-a:before{content:"\f109"}.ion-arrow-right-b:before{content:"\f10a"}.ion-arrow-right-c:before{content:"\f10b"}.ion-arrow-shrink:before{content:"\f267"}.ion-arrow-swap:before{content:"\f268"}.ion-arrow-up-a:before{content:"\f10c"}.ion-arrow-up-b:before{content:"\f10d"}.ion-arrow-up-c:before{content:"\f10e"}.ion-asterisk:before{content:"\f314"}.ion-at:before{content:"\f10f"}.ion-backspace:before{content:"\f3bf"}.ion-backspace-outline:before{content:"\f3be"}.ion-bag:before{content:"\f110"}.ion-battery-charging:before{content:"\f111"}.ion-battery-empty:before{content:"\f112"}.ion-battery-full:before{content:"\f113"}.ion-battery-half:before{content:"\f114"}.ion-battery-low:before{content:"\f115"}.ion-beaker:before{content:"\f269"}.ion-beer:before{content:"\f26a"}.ion-bluetooth:before{content:"\f116"}.ion-bonfire:before{content:"\f315"}.ion-bookmark:before{content:"\f26b"}.ion-bowtie:before{content:"\f3c0"}.ion-briefcase:before{content:"\f26c"}.ion-bug:before{content:"\f2be"}.ion-calculator:before{content:"\f26d"}.ion-calendar:before{content:"\f117"}.ion-camera:before{content:"\f118"}.ion-card:before{content:"\f119"}.ion-cash:before{content:"\f316"}.ion-chatbox:before{content:"\f11b"}.ion-chatbox-working:before{content:"\f11a"}.ion-chatboxes:before{content:"\f11c"}.ion-chatbubble:before{content:"\f11e"}.ion-chatbubble-working:before{content:"\f11d"}.ion-chatbubbles:before{content:"\f11f"}.ion-checkmark:before{content:"\f122"}.ion-checkmark-circled:before{content:"\f120"}.ion-checkmark-round:before{content:"\f121"}.ion-chevron-down:before{content:"\f123"}.ion-chevron-left:before{content:"\f124"}.ion-chevron-right:before{content:"\f125"}.ion-chevron-up:before{content:"\f126"}.ion-clipboard:before{content:"\f127"}.ion-clock:before{content:"\f26e"}.ion-close:before{content:"\f12a"}.ion-close-circled:before{content:"\f128"}.ion-close-round:before{content:"\f129"}.ion-closed-captioning:before{content:"\f317"}.ion-cloud:before{content:"\f12b"}.ion-code:before{content:"\f271"}.ion-code-download:before{content:"\f26f"}.ion-code-working:before{content:"\f270"}.ion-coffee:before{content:"\f272"}.ion-compass:before{content:"\f273"}.ion-compose:before{content:"\f12c"}.ion-connection-bars:before{content:"\f274"}.ion-contrast:before{content:"\f275"}.ion-crop:before{content:"\f3c1"}.ion-cube:before{content:"\f318"}.ion-disc:before{content:"\f12d"}.ion-document:before{content:"\f12f"}.ion-document-text:before{content:"\f12e"}.ion-drag:before{content:"\f130"}.ion-earth:before{content:"\f276"}.ion-easel:before{content:"\f3c2"}.ion-edit:before{content:"\f2bf"}.ion-egg:before{content:"\f277"}.ion-eject:before{content:"\f131"}.ion-email:before{content:"\f132"}.ion-email-unread:before{content:"\f3c3"}.ion-erlenmeyer-flask:before{content:"\f3c5"}.ion-erlenmeyer-flask-bubbles:before{content:"\f3c4"}.ion-eye:before{content:"\f133"}.ion-eye-disabled:before{content:"\f306"}.ion-female:before{content:"\f278"}.ion-filing:before{content:"\f134"}.ion-film-marker:before{content:"\f135"}.ion-fireball:before{content:"\f319"}.ion-flag:before{content:"\f279"}.ion-flame:before{content:"\f31a"}.ion-flash:before{content:"\f137"}.ion-flash-off:before{content:"\f136"}.ion-folder:before{content:"\f139"}.ion-fork:before{content:"\f27a"}.ion-fork-repo:before{content:"\f2c0"}.ion-forward:before{content:"\f13a"}.ion-funnel:before{content:"\f31b"}.ion-gear-a:before{content:"\f13d"}.ion-gear-b:before{content:"\f13e"}.ion-grid:before{content:"\f13f"}.ion-hammer:before{content:"\f27b"}.ion-happy:before{content:"\f31c"}.ion-happy-outline:before{content:"\f3c6"}.ion-headphone:before{content:"\f140"}.ion-heart:before{content:"\f141"}.ion-heart-broken:before{content:"\f31d"}.ion-help:before{content:"\f143"}.ion-help-buoy:before{content:"\f27c"}.ion-help-circled:before{content:"\f142"}.ion-home:before{content:"\f144"}.ion-icecream:before{content:"\f27d"}.ion-image:before{content:"\f147"}.ion-images:before{content:"\f148"}.ion-information:before{content:"\f14a"}.ion-information-circled:before{content:"\f149"}.ion-ionic:before{content:"\f14b"}.ion-ios-alarm:before{content:"\f3c8"}.ion-ios-alarm-outline:before{content:"\f3c7"}.ion-ios-albums:before{content:"\f3ca"}.ion-ios-albums-outline:before{content:"\f3c9"}.ion-ios-americanfootball:before{content:"\f3cc"}.ion-ios-americanfootball-outline:before{content:"\f3cb"}.ion-ios-analytics:before{content:"\f3ce"}.ion-ios-analytics-outline:before{content:"\f3cd"}.ion-ios-arrow-back:before{content:"\f3cf"}.ion-ios-arrow-down:before{content:"\f3d0"}.ion-ios-arrow-forward:before{content:"\f3d1"}.ion-ios-arrow-left:before{content:"\f3d2"}.ion-ios-arrow-right:before{content:"\f3d3"}.ion-ios-arrow-thin-down:before{content:"\f3d4"}.ion-ios-arrow-thin-left:before{content:"\f3d5"}.ion-ios-arrow-thin-right:before{content:"\f3d6"}.ion-ios-arrow-thin-up:before{content:"\f3d7"}.ion-ios-arrow-up:before{content:"\f3d8"}.ion-ios-at:before{content:"\f3da"}.ion-ios-at-outline:before{content:"\f3d9"}.ion-ios-barcode:before{content:"\f3dc"}.ion-ios-barcode-outline:before{content:"\f3db"}.ion-ios-baseball:before{content:"\f3de"}.ion-ios-baseball-outline:before{content:"\f3dd"}.ion-ios-basketball:before{content:"\f3e0"}.ion-ios-basketball-outline:before{content:"\f3df"}.ion-ios-bell:before{content:"\f3e2"}.ion-ios-bell-outline:before{content:"\f3e1"}.ion-ios-body:before{content:"\f3e4"}.ion-ios-body-outline:before{content:"\f3e3"}.ion-ios-bolt:before{content:"\f3e6"}.ion-ios-bolt-outline:before{content:"\f3e5"}.ion-ios-book:before{content:"\f3e8"}.ion-ios-book-outline:before{content:"\f3e7"}.ion-ios-bookmarks:before{content:"\f3ea"}.ion-ios-bookmarks-outline:before{content:"\f3e9"}.ion-ios-box:before{content:"\f3ec"}.ion-ios-box-outline:before{content:"\f3eb"}.ion-ios-briefcase:before{content:"\f3ee"}.ion-ios-briefcase-outline:before{content:"\f3ed"}.ion-ios-browsers:before{content:"\f3f0"}.ion-ios-browsers-outline:before{content:"\f3ef"}.ion-ios-calculator:before{content:"\f3f2"}.ion-ios-calculator-outline:before{content:"\f3f1"}.ion-ios-calendar:before{content:"\f3f4"}.ion-ios-calendar-outline:before{content:"\f3f3"}.ion-ios-camera:before{content:"\f3f6"}.ion-ios-camera-outline:before{content:"\f3f5"}.ion-ios-cart:before{content:"\f3f8"}.ion-ios-cart-outline:before{content:"\f3f7"}.ion-ios-chatboxes:before{content:"\f3fa"}.ion-ios-chatboxes-outline:before{content:"\f3f9"}.ion-ios-chatbubble:before{content:"\f3fc"}.ion-ios-chatbubble-outline:before{content:"\f3fb"}.ion-ios-checkmark:before{content:"\f3ff"}.ion-ios-checkmark-empty:before{content:"\f3fd"}.ion-ios-checkmark-outline:before{content:"\f3fe"}.ion-ios-circle-filled:before{content:"\f400"}.ion-ios-circle-outline:before{content:"\f401"}.ion-ios-clock:before{content:"\f403"}.ion-ios-clock-outline:before{content:"\f402"}.ion-ios-close:before{content:"\f406"}.ion-ios-close-empty:before{content:"\f404"}.ion-ios-close-outline:before{content:"\f405"}.ion-ios-cloud:before{content:"\f40c"}.ion-ios-cloud-download:before{content:"\f408"}.ion-ios-cloud-download-outline:before{content:"\f407"}.ion-ios-cloud-outline:before{content:"\f409"}.ion-ios-cloud-upload:before{content:"\f40b"}.ion-ios-cloud-upload-outline:before{content:"\f40a"}.ion-ios-cloudy:before{content:"\f410"}.ion-ios-cloudy-night:before{content:"\f40e"}.ion-ios-cloudy-night-outline:before{content:"\f40d"}.ion-ios-cloudy-outline:before{content:"\f40f"}.ion-ios-cog:before{content:"\f412"}.ion-ios-cog-outline:before{content:"\f411"}.ion-ios-color-filter:before{content:"\f414"}.ion-ios-color-filter-outline:before{content:"\f413"}.ion-ios-color-wand:before{content:"\f416"}.ion-ios-color-wand-outline:before{content:"\f415"}.ion-ios-compose:before{content:"\f418"}.ion-ios-compose-outline:before{content:"\f417"}.ion-ios-contact:before{content:"\f41a"}.ion-ios-contact-outline:before{content:"\f419"}.ion-ios-copy:before{content:"\f41c"}.ion-ios-copy-outline:before{content:"\f41b"}.ion-ios-crop:before{content:"\f41e"}.ion-ios-crop-strong:before{content:"\f41d"}.ion-ios-download:before{content:"\f420"}.ion-ios-download-outline:before{content:"\f41f"}.ion-ios-drag:before{content:"\f421"}.ion-ios-email:before{content:"\f423"}.ion-ios-email-outline:before{content:"\f422"}.ion-ios-eye:before{content:"\f425"}.ion-ios-eye-outline:before{content:"\f424"}.ion-ios-fastforward:before{content:"\f427"}.ion-ios-fastforward-outline:before{content:"\f426"}.ion-ios-filing:before{content:"\f429"}.ion-ios-filing-outline:before{content:"\f428"}.ion-ios-film:before{content:"\f42b"}.ion-ios-film-outline:before{content:"\f42a"}.ion-ios-flag:before{content:"\f42d"}.ion-ios-flag-outline:before{content:"\f42c"}.ion-ios-flame:before{content:"\f42f"}.ion-ios-flame-outline:before{content:"\f42e"}.ion-ios-flask:before{content:"\f431"}.ion-ios-flask-outline:before{content:"\f430"}.ion-ios-flower:before{content:"\f433"}.ion-ios-flower-outline:before{content:"\f432"}.ion-ios-folder:before{content:"\f435"}.ion-ios-folder-outline:before{content:"\f434"}.ion-ios-football:before{content:"\f437"}.ion-ios-football-outline:before{content:"\f436"}.ion-ios-game-controller-a:before{content:"\f439"}.ion-ios-game-controller-a-outline:before{content:"\f438"}.ion-ios-game-controller-b:before{content:"\f43b"}.ion-ios-game-controller-b-outline:before{content:"\f43a"}.ion-ios-gear:before{content:"\f43d"}.ion-ios-gear-outline:before{content:"\f43c"}.ion-ios-glasses:before{content:"\f43f"}.ion-ios-glasses-outline:before{content:"\f43e"}.ion-ios-grid-view:before{content:"\f441"}.ion-ios-grid-view-outline:before{content:"\f440"}.ion-ios-heart:before{content:"\f443"}.ion-ios-heart-outline:before{content:"\f442"}.ion-ios-help:before{content:"\f446"}.ion-ios-help-empty:before{content:"\f444"}.ion-ios-help-outline:before{content:"\f445"}.ion-ios-home:before{content:"\f448"}.ion-ios-home-outline:before{content:"\f447"}.ion-ios-infinite:before{content:"\f44a"}.ion-ios-infinite-outline:before{content:"\f449"}.ion-ios-information:before{content:"\f44d"}.ion-ios-information-empty:before{content:"\f44b"}.ion-ios-information-outline:before{content:"\f44c"}.ion-ios-ionic-outline:before{content:"\f44e"}.ion-ios-keypad:before{content:"\f450"}.ion-ios-keypad-outline:before{content:"\f44f"}.ion-ios-lightbulb:before{content:"\f452"}.ion-ios-lightbulb-outline:before{content:"\f451"}.ion-ios-list:before{content:"\f454"}.ion-ios-list-outline:before{content:"\f453"}.ion-ios-location:before{content:"\f456"}.ion-ios-location-outline:before{content:"\f455"}.ion-ios-locked:before{content:"\f458"}.ion-ios-locked-outline:before{content:"\f457"}.ion-ios-loop:before{content:"\f45a"}.ion-ios-loop-strong:before{content:"\f459"}.ion-ios-medical:before{content:"\f45c"}.ion-ios-medical-outline:before{content:"\f45b"}.ion-ios-medkit:before{content:"\f45e"}.ion-ios-medkit-outline:before{content:"\f45d"}.ion-ios-mic:before{content:"\f461"}.ion-ios-mic-off:before{content:"\f45f"}.ion-ios-mic-outline:before{content:"\f460"}.ion-ios-minus:before{content:"\f464"}.ion-ios-minus-empty:before{content:"\f462"}.ion-ios-minus-outline:before{content:"\f463"}.ion-ios-monitor:before{content:"\f466"}.ion-ios-monitor-outline:before{content:"\f465"}.ion-ios-moon:before{content:"\f468"}.ion-ios-moon-outline:before{content:"\f467"}.ion-ios-more:before{content:"\f46a"}.ion-ios-more-outline:before{content:"\f469"}.ion-ios-musical-note:before{content:"\f46b"}.ion-ios-musical-notes:before{content:"\f46c"}.ion-ios-navigate:before{content:"\f46e"}.ion-ios-navigate-outline:before{content:"\f46d"}.ion-ios-nutrition:before{content:"\f470"}.ion-ios-nutrition-outline:before{content:"\f46f"}.ion-ios-paper:before{content:"\f472"}.ion-ios-paper-outline:before{content:"\f471"}.ion-ios-paperplane:before{content:"\f474"}.ion-ios-paperplane-outline:before{content:"\f473"}.ion-ios-partlysunny:before{content:"\f476"}.ion-ios-partlysunny-outline:before{content:"\f475"}.ion-ios-pause:before{content:"\f478"}.ion-ios-pause-outline:before{content:"\f477"}.ion-ios-paw:before{content:"\f47a"}.ion-ios-paw-outline:before{content:"\f479"}.ion-ios-people:before{content:"\f47c"}.ion-ios-people-outline:before{content:"\f47b"}.ion-ios-person:before{content:"\f47e"}.ion-ios-person-outline:before{content:"\f47d"}.ion-ios-personadd:before{content:"\f480"}.ion-ios-personadd-outline:before{content:"\f47f"}.ion-ios-photos:before{content:"\f482"}.ion-ios-photos-outline:before{content:"\f481"}.ion-ios-pie:before{content:"\f484"}.ion-ios-pie-outline:before{content:"\f483"}.ion-ios-pint:before{content:"\f486"}.ion-ios-pint-outline:before{content:"\f485"}.ion-ios-play:before{content:"\f488"}.ion-ios-play-outline:before{content:"\f487"}.ion-ios-plus:before{content:"\f48b"}.ion-ios-plus-empty:before{content:"\f489"}.ion-ios-plus-outline:before{content:"\f48a"}.ion-ios-pricetag:before{content:"\f48d"}.ion-ios-pricetag-outline:before{content:"\f48c"}.ion-ios-pricetags:before{content:"\f48f"}.ion-ios-pricetags-outline:before{content:"\f48e"}.ion-ios-printer:before{content:"\f491"}.ion-ios-printer-outline:before{content:"\f490"}.ion-ios-pulse:before{content:"\f493"}.ion-ios-pulse-strong:before{content:"\f492"}.ion-ios-rainy:before{content:"\f495"}.ion-ios-rainy-outline:before{content:"\f494"}.ion-ios-recording:before{content:"\f497"}.ion-ios-recording-outline:before{content:"\f496"}.ion-ios-redo:before{content:"\f499"}.ion-ios-redo-outline:before{content:"\f498"}.ion-ios-refresh:before{content:"\f49c"}.ion-ios-refresh-empty:before{content:"\f49a"}.ion-ios-refresh-outline:before{content:"\f49b"}.ion-ios-reload:before{content:"\f49d"}.ion-ios-reverse-camera:before{content:"\f49f"}.ion-ios-reverse-camera-outline:before{content:"\f49e"}.ion-ios-rewind:before{content:"\f4a1"}.ion-ios-rewind-outline:before{content:"\f4a0"}.ion-ios-rose:before{content:"\f4a3"}.ion-ios-rose-outline:before{content:"\f4a2"}.ion-ios-search:before{content:"\f4a5"}.ion-ios-search-strong:before{content:"\f4a4"}.ion-ios-settings:before{content:"\f4a7"}.ion-ios-settings-strong:before{content:"\f4a6"}.ion-ios-shuffle:before{content:"\f4a9"}.ion-ios-shuffle-strong:before{content:"\f4a8"}.ion-ios-skipbackward:before{content:"\f4ab"}.ion-ios-skipbackward-outline:before{content:"\f4aa"}.ion-ios-skipforward:before{content:"\f4ad"}.ion-ios-skipforward-outline:before{content:"\f4ac"}.ion-ios-snowy:before{content:"\f4ae"}.ion-ios-speedometer:before{content:"\f4b0"}.ion-ios-speedometer-outline:before{content:"\f4af"}.ion-ios-star:before{content:"\f4b3"}.ion-ios-star-half:before{content:"\f4b1"}.ion-ios-star-outline:before{content:"\f4b2"}.ion-ios-stopwatch:before{content:"\f4b5"}.ion-ios-stopwatch-outline:before{content:"\f4b4"}.ion-ios-sunny:before{content:"\f4b7"}.ion-ios-sunny-outline:before{content:"\f4b6"}.ion-ios-telephone:before{content:"\f4b9"}.ion-ios-telephone-outline:before{content:"\f4b8"}.ion-ios-tennisball:before{content:"\f4bb"}.ion-ios-tennisball-outline:before{content:"\f4ba"}.ion-ios-thunderstorm:before{content:"\f4bd"}.ion-ios-thunderstorm-outline:before{content:"\f4bc"}.ion-ios-time:before{content:"\f4bf"}.ion-ios-time-outline:before{content:"\f4be"}.ion-ios-timer:before{content:"\f4c1"}.ion-ios-timer-outline:before{content:"\f4c0"}.ion-ios-toggle:before{content:"\f4c3"}.ion-ios-toggle-outline:before{content:"\f4c2"}.ion-ios-trash:before{content:"\f4c5"}.ion-ios-trash-outline:before{content:"\f4c4"}.ion-ios-undo:before{content:"\f4c7"}.ion-ios-undo-outline:before{content:"\f4c6"}.ion-ios-unlocked:before{content:"\f4c9"}.ion-ios-unlocked-outline:before{content:"\f4c8"}.ion-ios-upload:before{content:"\f4cb"}.ion-ios-upload-outline:before{content:"\f4ca"}.ion-ios-videocam:before{content:"\f4cd"}.ion-ios-videocam-outline:before{content:"\f4cc"}.ion-ios-volume-high:before{content:"\f4ce"}.ion-ios-volume-low:before{content:"\f4cf"}.ion-ios-wineglass:before{content:"\f4d1"}.ion-ios-wineglass-outline:before{content:"\f4d0"}.ion-ios-world:before{content:"\f4d3"}.ion-ios-world-outline:before{content:"\f4d2"}.ion-ipad:before{content:"\f1f9"}.ion-iphone:before{content:"\f1fa"}.ion-ipod:before{content:"\f1fb"}.ion-jet:before{content:"\f295"}.ion-key:before{content:"\f296"}.ion-knife:before{content:"\f297"}.ion-laptop:before{content:"\f1fc"}.ion-leaf:before{content:"\f1fd"}.ion-levels:before{content:"\f298"}.ion-lightbulb:before{content:"\f299"}.ion-link:before{content:"\f1fe"}.ion-load-a:before{content:"\f29a"}.ion-load-b:before{content:"\f29b"}.ion-load-c:before{content:"\f29c"}.ion-load-d:before{content:"\f29d"}.ion-location:before{content:"\f1ff"}.ion-lock-combination:before{content:"\f4d4"}.ion-locked:before{content:"\f200"}.ion-log-in:before{content:"\f29e"}.ion-log-out:before{content:"\f29f"}.ion-loop:before{content:"\f201"}.ion-magnet:before{content:"\f2a0"}.ion-male:before{content:"\f2a1"}.ion-man:before{content:"\f202"}.ion-map:before{content:"\f203"}.ion-medkit:before{content:"\f2a2"}.ion-merge:before{content:"\f33f"}.ion-mic-a:before{content:"\f204"}.ion-mic-b:before{content:"\f205"}.ion-mic-c:before{content:"\f206"}.ion-minus:before{content:"\f209"}.ion-minus-circled:before{content:"\f207"}.ion-minus-round:before{content:"\f208"}.ion-model-s:before{content:"\f2c1"}.ion-monitor:before{content:"\f20a"}.ion-more:before{content:"\f20b"}.ion-mouse:before{content:"\f340"}.ion-music-note:before{content:"\f20c"}.ion-navicon:before{content:"\f20e"}.ion-navicon-round:before{content:"\f20d"}.ion-navigate:before{content:"\f2a3"}.ion-network:before{content:"\f341"}.ion-no-smoking:before{content:"\f2c2"}.ion-nuclear:before{content:"\f2a4"}.ion-outlet:before{content:"\f342"}.ion-paintbrush:before{content:"\f4d5"}.ion-paintbucket:before{content:"\f4d6"}.ion-paper-airplane:before{content:"\f2c3"}.ion-paperclip:before{content:"\f20f"}.ion-pause:before{content:"\f210"}.ion-person:before{content:"\f213"}.ion-person-add:before{content:"\f211"}.ion-person-stalker:before{content:"\f212"}.ion-pie-graph:before{content:"\f2a5"}.ion-pin:before{content:"\f2a6"}.ion-pinpoint:before{content:"\f2a7"}.ion-pizza:before{content:"\f2a8"}.ion-plane:before{content:"\f214"}.ion-planet:before{content:"\f343"}.ion-play:before{content:"\f215"}.ion-playstation:before{content:"\f30a"}.ion-plus:before{content:"\f218"}.ion-plus-circled:before{content:"\f216"}.ion-plus-round:before{content:"\f217"}.ion-podium:before{content:"\f344"}.ion-pound:before{content:"\f219"}.ion-power:before{content:"\f2a9"}.ion-pricetag:before{content:"\f2aa"}.ion-pricetags:before{content:"\f2ab"}.ion-printer:before{content:"\f21a"}.ion-pull-request:before{content:"\f345"}.ion-qr-scanner:before{content:"\f346"}.ion-quote:before{content:"\f347"}.ion-radio-waves:before{content:"\f2ac"}.ion-record:before{content:"\f21b"}.ion-refresh:before{content:"\f21c"}.ion-reply:before{content:"\f21e"}.ion-reply-all:before{content:"\f21d"}.ion-ribbon-a:before{content:"\f348"}.ion-ribbon-b:before{content:"\f349"}.ion-sad:before{content:"\f34a"}.ion-sad-outline:before{content:"\f4d7"}.ion-scissors:before{content:"\f34b"}.ion-search:before{content:"\f21f"}.ion-settings:before{content:"\f2ad"}.ion-share:before{content:"\f220"}.ion-shuffle:before{content:"\f221"}.ion-skip-backward:before{content:"\f222"}.ion-skip-forward:before{content:"\f223"}.ion-social-android:before{content:"\f225"}.ion-social-android-outline:before{content:"\f224"}.ion-social-angular:before{content:"\f4d9"}.ion-social-angular-outline:before{content:"\f4d8"}.ion-social-apple:before{content:"\f227"}.ion-social-apple-outline:before{content:"\f226"}.ion-social-bitcoin:before{content:"\f2af"}.ion-social-bitcoin-outline:before{content:"\f2ae"}.ion-social-buffer:before{content:"\f229"}.ion-social-buffer-outline:before{content:"\f228"}.ion-social-chrome:before{content:"\f4db"}.ion-social-chrome-outline:before{content:"\f4da"}.ion-social-codepen:before{content:"\f4dd"}.ion-social-codepen-outline:before{content:"\f4dc"}.ion-social-css3:before{content:"\f4df"}.ion-social-css3-outline:before{content:"\f4de"}.ion-social-designernews:before{content:"\f22b"}.ion-social-designernews-outline:before{content:"\f22a"}.ion-social-dribbble:before{content:"\f22d"}.ion-social-dribbble-outline:before{content:"\f22c"}.ion-social-dropbox:before{content:"\f22f"}.ion-social-dropbox-outline:before{content:"\f22e"}.ion-social-euro:before{content:"\f4e1"}.ion-social-euro-outline:before{content:"\f4e0"}.ion-social-facebook:before{content:"\f231"}.ion-social-facebook-outline:before{content:"\f230"}.ion-social-foursquare:before{content:"\f34d"}.ion-social-foursquare-outline:before{content:"\f34c"}.ion-social-freebsd-devil:before{content:"\f2c4"}.ion-social-github:before{content:"\f233"}.ion-social-github-outline:before{content:"\f232"}.ion-social-google:before{content:"\f34f"}.ion-social-google-outline:before{content:"\f34e"}.ion-social-googleplus:before{content:"\f235"}.ion-social-googleplus-outline:before{content:"\f234"}.ion-social-hackernews:before{content:"\f237"}.ion-social-hackernews-outline:before{content:"\f236"}.ion-social-html5:before{content:"\f4e3"}.ion-social-html5-outline:before{content:"\f4e2"}.ion-social-instagram:before{content:"\f351"}.ion-social-instagram-outline:before{content:"\f350"}.ion-social-javascript:before{content:"\f4e5"}.ion-social-javascript-outline:before{content:"\f4e4"}.ion-social-linkedin:before{content:"\f239"}.ion-social-linkedin-outline:before{content:"\f238"}.ion-social-markdown:before{content:"\f4e6"}.ion-social-nodejs:before{content:"\f4e7"}.ion-social-octocat:before{content:"\f4e8"}.ion-social-pinterest:before{content:"\f2b1"}.ion-social-pinterest-outline:before{content:"\f2b0"}.ion-social-python:before{content:"\f4e9"}.ion-social-reddit:before{content:"\f23b"}.ion-social-reddit-outline:before{content:"\f23a"}.ion-social-rss:before{content:"\f23d"}.ion-social-rss-outline:before{content:"\f23c"}.ion-social-sass:before{content:"\f4ea"}.ion-social-skype:before{content:"\f23f"}.ion-social-skype-outline:before{content:"\f23e"}.ion-social-snapchat:before{content:"\f4ec"}.ion-social-snapchat-outline:before{content:"\f4eb"}.ion-social-tumblr:before{content:"\f241"}.ion-social-tumblr-outline:before{content:"\f240"}.ion-social-tux:before{content:"\f2c5"}.ion-social-twitch:before{content:"\f4ee"}.ion-social-twitch-outline:before{content:"\f4ed"}.ion-social-twitter:before{content:"\f243"}.ion-social-twitter-outline:before{content:"\f242"}.ion-social-usd:before{content:"\f353"}.ion-social-usd-outline:before{content:"\f352"}.ion-social-vimeo:before{content:"\f245"}.ion-social-vimeo-outline:before{content:"\f244"}.ion-social-whatsapp:before{content:"\f4f0"}.ion-social-whatsapp-outline:before{content:"\f4ef"}.ion-social-windows:before{content:"\f247"}.ion-social-windows-outline:before{content:"\f246"}.ion-social-wordpress:before{content:"\f249"}.ion-social-wordpress-outline:before{content:"\f248"}.ion-social-yahoo:before{content:"\f24b"}.ion-social-yahoo-outline:before{content:"\f24a"}.ion-social-yen:before{content:"\f4f2"}.ion-social-yen-outline:before{content:"\f4f1"}.ion-social-youtube:before{content:"\f24d"}.ion-social-youtube-outline:before{content:"\f24c"}.ion-soup-can:before{content:"\f4f4"}.ion-soup-can-outline:before{content:"\f4f3"}.ion-speakerphone:before{content:"\f2b2"}.ion-speedometer:before{content:"\f2b3"}.ion-spoon:before{content:"\f2b4"}.ion-star:before{content:"\f24e"}.ion-stats-bars:before{content:"\f2b5"}.ion-steam:before{content:"\f30b"}.ion-stop:before{content:"\f24f"}.ion-thermometer:before{content:"\f2b6"}.ion-thumbsdown:before{content:"\f250"}.ion-thumbsup:before{content:"\f251"}.ion-toggle:before{content:"\f355"}.ion-toggle-filled:before{content:"\f354"}.ion-transgender:before{content:"\f4f5"}.ion-trash-a:before{content:"\f252"}.ion-trash-b:before{content:"\f253"}.ion-trophy:before{content:"\f356"}.ion-tshirt:before{content:"\f4f7"}.ion-tshirt-outline:before{content:"\f4f6"}.ion-umbrella:before{content:"\f2b7"}.ion-university:before{content:"\f357"}.ion-unlocked:before{content:"\f254"}.ion-upload:before{content:"\f255"}.ion-usb:before{content:"\f2b8"}.ion-videocamera:before{content:"\f256"}.ion-volume-high:before{content:"\f257"}.ion-volume-low:before{content:"\f258"}.ion-volume-medium:before{content:"\f259"}.ion-volume-mute:before{content:"\f25a"}.ion-wand:before{content:"\f358"}.ion-waterdrop:before{content:"\f25b"}.ion-wifi:before{content:"\f25c"}.ion-wineglass:before{content:"\f2b9"}.ion-woman:before{content:"\f25d"}.ion-wrench:before{content:"\f2ba"}.ion-xbox:before{content:"\f30c"} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.eot b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.eot new file mode 100644 index 0000000..92a3f20 Binary files /dev/null and b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.eot differ diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.svg b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.svg new file mode 100644 index 0000000..49fc8f3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.svg @@ -0,0 +1,2230 @@ + + + + + +Created by FontForge 20120731 at Thu Dec 4 09:51:48 2014 + By Adam Bradley +Created by Adam Bradley with FontForge 2.0 (http://fontforge.sf.net) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.ttf b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.ttf new file mode 100644 index 0000000..c4e4632 Binary files /dev/null and b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.ttf differ diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.woff b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.woff new file mode 100644 index 0000000..5f3a14e Binary files /dev/null and b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/Ionicons/fonts/ionicons.woff differ diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js new file mode 100644 index 0000000..234f9b3 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/pace.min.js @@ -0,0 +1,2 @@ +/*! pace 1.0.2 */ +(function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X=[].slice,Y={}.hasOwnProperty,Z=function(a,b){function c(){this.constructor=a}for(var d in b)Y.call(b,d)&&(a[d]=b[d]);return c.prototype=b.prototype,a.prototype=new c,a.__super__=b.prototype,a},$=[].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1};for(u={catchupTime:100,initialRate:.03,minTime:250,ghostTime:100,maxProgressPerFrame:20,easeFactor:1.25,startOnPageLoad:!0,restartOnPushState:!0,restartOnRequestAfter:500,target:"body",elements:{checkInterval:100,selectors:["body"]},eventLag:{minSamples:10,sampleCount:3,lagThreshold:3},ajax:{trackMethods:["GET"],trackWebSockets:!0,ignoreURLs:[]}},C=function(){var a;return null!=(a="undefined"!=typeof performance&&null!==performance&&"function"==typeof performance.now?performance.now():void 0)?a:+new Date},E=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame,t=window.cancelAnimationFrame||window.mozCancelAnimationFrame,null==E&&(E=function(a){return setTimeout(a,50)},t=function(a){return clearTimeout(a)}),G=function(a){var b,c;return b=C(),(c=function(){var d;return d=C()-b,d>=33?(b=C(),a(d,function(){return E(c)})):setTimeout(c,33-d)})()},F=function(){var a,b,c;return c=arguments[0],b=arguments[1],a=3<=arguments.length?X.call(arguments,2):[],"function"==typeof c[b]?c[b].apply(c,a):c[b]},v=function(){var a,b,c,d,e,f,g;for(b=arguments[0],d=2<=arguments.length?X.call(arguments,1):[],f=0,g=d.length;g>f;f++)if(c=d[f])for(a in c)Y.call(c,a)&&(e=c[a],null!=b[a]&&"object"==typeof b[a]&&null!=e&&"object"==typeof e?v(b[a],e):b[a]=e);return b},q=function(a){var b,c,d,e,f;for(c=b=0,e=0,f=a.length;f>e;e++)d=a[e],c+=Math.abs(d),b++;return c/b},x=function(a,b){var c,d,e;if(null==a&&(a="options"),null==b&&(b=!0),e=document.querySelector("[data-pace-"+a+"]")){if(c=e.getAttribute("data-pace-"+a),!b)return c;try{return JSON.parse(c)}catch(f){return d=f,"undefined"!=typeof console&&null!==console?console.error("Error parsing inline pace options",d):void 0}}},g=function(){function a(){}return a.prototype.on=function(a,b,c,d){var e;return null==d&&(d=!1),null==this.bindings&&(this.bindings={}),null==(e=this.bindings)[a]&&(e[a]=[]),this.bindings[a].push({handler:b,ctx:c,once:d})},a.prototype.once=function(a,b,c){return this.on(a,b,c,!0)},a.prototype.off=function(a,b){var c,d,e;if(null!=(null!=(d=this.bindings)?d[a]:void 0)){if(null==b)return delete this.bindings[a];for(c=0,e=[];cQ;Q++)K=U[Q],D[K]===!0&&(D[K]=u[K]);i=function(a){function b(){return V=b.__super__.constructor.apply(this,arguments)}return Z(b,a),b}(Error),b=function(){function a(){this.progress=0}return a.prototype.getElement=function(){var a;if(null==this.el){if(a=document.querySelector(D.target),!a)throw new i;this.el=document.createElement("div"),this.el.className="pace pace-active",document.body.className=document.body.className.replace(/pace-done/g,""),document.body.className+=" pace-running",this.el.innerHTML='

\n
\n
\n
',null!=a.firstChild?a.insertBefore(this.el,a.firstChild):a.appendChild(this.el)}return this.el},a.prototype.finish=function(){var a;return a=this.getElement(),a.className=a.className.replace("pace-active",""),a.className+=" pace-inactive",document.body.className=document.body.className.replace("pace-running",""),document.body.className+=" pace-done"},a.prototype.update=function(a){return this.progress=a,this.render()},a.prototype.destroy=function(){try{this.getElement().parentNode.removeChild(this.getElement())}catch(a){i=a}return this.el=void 0},a.prototype.render=function(){var a,b,c,d,e,f,g;if(null==document.querySelector(D.target))return!1;for(a=this.getElement(),d="translate3d("+this.progress+"%, 0, 0)",g=["webkitTransform","msTransform","transform"],e=0,f=g.length;f>e;e++)b=g[e],a.children[0].style[b]=d;return(!this.lastRenderedProgress||this.lastRenderedProgress|0!==this.progress|0)&&(a.children[0].setAttribute("data-progress-text",""+(0|this.progress)+"%"),this.progress>=100?c="99":(c=this.progress<10?"0":"",c+=0|this.progress),a.children[0].setAttribute("data-progress",""+c)),this.lastRenderedProgress=this.progress},a.prototype.done=function(){return this.progress>=100},a}(),h=function(){function a(){this.bindings={}}return a.prototype.trigger=function(a,b){var c,d,e,f,g;if(null!=this.bindings[a]){for(f=this.bindings[a],g=[],d=0,e=f.length;e>d;d++)c=f[d],g.push(c.call(this,b));return g}},a.prototype.on=function(a,b){var c;return null==(c=this.bindings)[a]&&(c[a]=[]),this.bindings[a].push(b)},a}(),P=window.XMLHttpRequest,O=window.XDomainRequest,N=window.WebSocket,w=function(a,b){var c,d,e;e=[];for(d in b.prototype)try{e.push(null==a[d]&&"function"!=typeof b[d]?"function"==typeof Object.defineProperty?Object.defineProperty(a,d,{get:function(){return b.prototype[d]},configurable:!0,enumerable:!0}):a[d]=b.prototype[d]:void 0)}catch(f){c=f}return e},A=[],j.ignore=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("ignore"),c=b.apply(null,a),A.shift(),c},j.track=function(){var a,b,c;return b=arguments[0],a=2<=arguments.length?X.call(arguments,1):[],A.unshift("track"),c=b.apply(null,a),A.shift(),c},J=function(a){var b;if(null==a&&(a="GET"),"track"===A[0])return"force";if(!A.length&&D.ajax){if("socket"===a&&D.ajax.trackWebSockets)return!0;if(b=a.toUpperCase(),$.call(D.ajax.trackMethods,b)>=0)return!0}return!1},k=function(a){function b(){var a,c=this;b.__super__.constructor.apply(this,arguments),a=function(a){var b;return b=a.open,a.open=function(d,e){return J(d)&&c.trigger("request",{type:d,url:e,request:a}),b.apply(a,arguments)}},window.XMLHttpRequest=function(b){var c;return c=new P(b),a(c),c};try{w(window.XMLHttpRequest,P)}catch(d){}if(null!=O){window.XDomainRequest=function(){var b;return b=new O,a(b),b};try{w(window.XDomainRequest,O)}catch(d){}}if(null!=N&&D.ajax.trackWebSockets){window.WebSocket=function(a,b){var d;return d=null!=b?new N(a,b):new N(a),J("socket")&&c.trigger("request",{type:"socket",url:a,protocols:b,request:d}),d};try{w(window.WebSocket,N)}catch(d){}}}return Z(b,a),b}(h),R=null,y=function(){return null==R&&(R=new k),R},I=function(a){var b,c,d,e;for(e=D.ajax.ignoreURLs,c=0,d=e.length;d>c;c++)if(b=e[c],"string"==typeof b){if(-1!==a.indexOf(b))return!0}else if(b.test(a))return!0;return!1},y().on("request",function(b){var c,d,e,f,g;return f=b.type,e=b.request,g=b.url,I(g)?void 0:j.running||D.restartOnRequestAfter===!1&&"force"!==J(f)?void 0:(d=arguments,c=D.restartOnRequestAfter||0,"boolean"==typeof c&&(c=0),setTimeout(function(){var b,c,g,h,i,k;if(b="socket"===f?e.readyState<2:0<(h=e.readyState)&&4>h){for(j.restart(),i=j.sources,k=[],c=0,g=i.length;g>c;c++){if(K=i[c],K instanceof a){K.watch.apply(K,d);break}k.push(void 0)}return k}},c))}),a=function(){function a(){var a=this;this.elements=[],y().on("request",function(){return a.watch.apply(a,arguments)})}return a.prototype.watch=function(a){var b,c,d,e;return d=a.type,b=a.request,e=a.url,I(e)?void 0:(c="socket"===d?new n(b):new o(b),this.elements.push(c))},a}(),o=function(){function a(a){var b,c,d,e,f,g,h=this;if(this.progress=0,null!=window.ProgressEvent)for(c=null,a.addEventListener("progress",function(a){return h.progress=a.lengthComputable?100*a.loaded/a.total:h.progress+(100-h.progress)/2},!1),g=["load","abort","timeout","error"],d=0,e=g.length;e>d;d++)b=g[d],a.addEventListener(b,function(){return h.progress=100},!1);else f=a.onreadystatechange,a.onreadystatechange=function(){var b;return 0===(b=a.readyState)||4===b?h.progress=100:3===a.readyState&&(h.progress=50),"function"==typeof f?f.apply(null,arguments):void 0}}return a}(),n=function(){function a(a){var b,c,d,e,f=this;for(this.progress=0,e=["error","open"],c=0,d=e.length;d>c;c++)b=e[c],a.addEventListener(b,function(){return f.progress=100},!1)}return a}(),d=function(){function a(a){var b,c,d,f;for(null==a&&(a={}),this.elements=[],null==a.selectors&&(a.selectors=[]),f=a.selectors,c=0,d=f.length;d>c;c++)b=f[c],this.elements.push(new e(b))}return a}(),e=function(){function a(a){this.selector=a,this.progress=0,this.check()}return a.prototype.check=function(){var a=this;return document.querySelector(this.selector)?this.done():setTimeout(function(){return a.check()},D.elements.checkInterval)},a.prototype.done=function(){return this.progress=100},a}(),c=function(){function a(){var a,b,c=this;this.progress=null!=(b=this.states[document.readyState])?b:100,a=document.onreadystatechange,document.onreadystatechange=function(){return null!=c.states[document.readyState]&&(c.progress=c.states[document.readyState]),"function"==typeof a?a.apply(null,arguments):void 0}}return a.prototype.states={loading:0,interactive:50,complete:100},a}(),f=function(){function a(){var a,b,c,d,e,f=this;this.progress=0,a=0,e=[],d=0,c=C(),b=setInterval(function(){var g;return g=C()-c-50,c=C(),e.push(g),e.length>D.eventLag.sampleCount&&e.shift(),a=q(e),++d>=D.eventLag.minSamples&&a=100&&(this.done=!0),b===this.last?this.sinceLastUpdate+=a:(this.sinceLastUpdate&&(this.rate=(b-this.last)/this.sinceLastUpdate),this.catchup=(b-this.progress)/D.catchupTime,this.sinceLastUpdate=0,this.last=b),b>this.progress&&(this.progress+=this.catchup*a),c=1-Math.pow(this.progress/100,D.easeFactor),this.progress+=c*this.rate*a,this.progress=Math.min(this.lastProgress+D.maxProgressPerFrame,this.progress),this.progress=Math.max(0,this.progress),this.progress=Math.min(100,this.progress),this.lastProgress=this.progress,this.progress},a}(),L=null,H=null,r=null,M=null,p=null,s=null,j.running=!1,z=function(){return D.restartOnPushState?j.restart():void 0},null!=window.history.pushState&&(T=window.history.pushState,window.history.pushState=function(){return z(),T.apply(window.history,arguments)}),null!=window.history.replaceState&&(W=window.history.replaceState,window.history.replaceState=function(){return z(),W.apply(window.history,arguments)}),l={ajax:a,elements:d,document:c,eventLag:f},(B=function(){var a,c,d,e,f,g,h,i;for(j.sources=L=[],g=["ajax","elements","document","eventLag"],c=0,e=g.length;e>c;c++)a=g[c],D[a]!==!1&&L.push(new l[a](D[a]));for(i=null!=(h=D.extraSources)?h:[],d=0,f=i.length;f>d;d++)K=i[d],L.push(new K(D));return j.bar=r=new b,H=[],M=new m})(),j.stop=function(){return j.trigger("stop"),j.running=!1,r.destroy(),s=!0,null!=p&&("function"==typeof t&&t(p),p=null),B()},j.restart=function(){return j.trigger("restart"),j.stop(),j.start()},j.go=function(){var a;return j.running=!0,r.render(),a=C(),s=!1,p=G(function(b,c){var d,e,f,g,h,i,k,l,n,o,p,q,t,u,v,w;for(l=100-r.progress,e=p=0,f=!0,i=q=0,u=L.length;u>q;i=++q)for(K=L[i],o=null!=H[i]?H[i]:H[i]=[],h=null!=(w=K.elements)?w:[K],k=t=0,v=h.length;v>t;k=++t)g=h[k],n=null!=o[k]?o[k]:o[k]=new m(g),f&=n.done,n.done||(e++,p+=n.tick(b));return d=p/e,r.update(M.tick(b,d)),r.done()||f||s?(r.update(100),j.trigger("done"),setTimeout(function(){return r.finish(),j.running=!1,j.trigger("hide")},Math.max(D.ghostTime,Math.max(D.minTime-(C()-a),0)))):c()})},j.start=function(a){v(D,a),j.running=!0;try{r.render()}catch(b){i=b}return document.querySelector(".pace")?(j.trigger("start"),j.go()):setTimeout(j.start,50)},"function"==typeof define&&define.amd?define(["pace"],function(){return j}):"object"==typeof exports?module.exports=j:D.startOnPageLoad&&j.start()}).call(this); \ No newline at end of file diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css new file mode 100644 index 0000000..d9bca46 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css @@ -0,0 +1,77 @@ +/* This is a compiled file, you should be editing the file in the templates directory */ +.pace { + -webkit-pointer-events: none; + pointer-events: none; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.pace-inactive { + display: none; +} + +.pace .pace-progress { + background: #2299dd; + position: fixed; + z-index: 2000; + top: 0; + right: 100%; + width: 100%; + height: 2px; +} + +.pace .pace-progress-inner { + display: block; + position: absolute; + right: 0px; + width: 100px; + height: 100%; + box-shadow: 0 0 10px #2299dd, 0 0 5px #2299dd; + opacity: 1.0; + -webkit-transform: rotate(3deg) translate(0px, -4px); + -moz-transform: rotate(3deg) translate(0px, -4px); + -ms-transform: rotate(3deg) translate(0px, -4px); + -o-transform: rotate(3deg) translate(0px, -4px); + transform: rotate(3deg) translate(0px, -4px); +} + +.pace .pace-activity { + display: block; + position: fixed; + z-index: 2000; + top: 15px; + right: 15px; + width: 14px; + height: 14px; + border: solid 2px transparent; + border-top-color: #2299dd; + border-left-color: #2299dd; + border-radius: 10px; + -webkit-animation: pace-spinner 400ms linear infinite; + -moz-animation: pace-spinner 400ms linear infinite; + -ms-animation: pace-spinner 400ms linear infinite; + -o-animation: pace-spinner 400ms linear infinite; + animation: pace-spinner 400ms linear infinite; +} + +@-webkit-keyframes pace-spinner { + 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } + 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } +} +@-moz-keyframes pace-spinner { + 0% { -moz-transform: rotate(0deg); transform: rotate(0deg); } + 100% { -moz-transform: rotate(360deg); transform: rotate(360deg); } +} +@-o-keyframes pace-spinner { + 0% { -o-transform: rotate(0deg); transform: rotate(0deg); } + 100% { -o-transform: rotate(360deg); transform: rotate(360deg); } +} +@-ms-keyframes pace-spinner { + 0% { -ms-transform: rotate(0deg); transform: rotate(0deg); } + 100% { -ms-transform: rotate(360deg); transform: rotate(360deg); } +} +@keyframes pace-spinner { + 0% { transform: rotate(0deg); transform: rotate(0deg); } + 100% { transform: rotate(360deg); transform: rotate(360deg); } +} diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css new file mode 100644 index 0000000..86f4b77 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css @@ -0,0 +1,269 @@ +.daterangepicker { + position: absolute; + color: inherit; + background-color: #fff; + border-radius: 4px; + width: 278px; + padding: 4px; + margin-top: 1px; + top: 100px; + left: 20px; + /* Calendars */ } + .daterangepicker:before, .daterangepicker:after { + position: absolute; + display: inline-block; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; } + .daterangepicker:before { + top: -7px; + border-right: 7px solid transparent; + border-left: 7px solid transparent; + border-bottom: 7px solid #ccc; } + .daterangepicker:after { + top: -6px; + border-right: 6px solid transparent; + border-bottom: 6px solid #fff; + border-left: 6px solid transparent; } + .daterangepicker.opensleft:before { + right: 9px; } + .daterangepicker.opensleft:after { + right: 10px; } + .daterangepicker.openscenter:before { + left: 0; + right: 0; + width: 0; + margin-left: auto; + margin-right: auto; } + .daterangepicker.openscenter:after { + left: 0; + right: 0; + width: 0; + margin-left: auto; + margin-right: auto; } + .daterangepicker.opensright:before { + left: 9px; } + .daterangepicker.opensright:after { + left: 10px; } + .daterangepicker.dropup { + margin-top: -5px; } + .daterangepicker.dropup:before { + top: initial; + bottom: -7px; + border-bottom: initial; + border-top: 7px solid #ccc; } + .daterangepicker.dropup:after { + top: initial; + bottom: -6px; + border-bottom: initial; + border-top: 6px solid #fff; } + .daterangepicker.dropdown-menu { + max-width: none; + z-index: 3001; } + .daterangepicker.single .ranges, .daterangepicker.single .calendar { + float: none; } + .daterangepicker.show-calendar .calendar { + display: block; } + .daterangepicker .calendar { + display: none; + max-width: 270px; + margin: 4px; } + .daterangepicker .calendar.single .calendar-table { + border: none; } + .daterangepicker .calendar th, .daterangepicker .calendar td { + white-space: nowrap; + text-align: center; + min-width: 32px; } + .daterangepicker .calendar-table { + border: 1px solid #fff; + padding: 4px; + border-radius: 4px; + background-color: #fff; } + .daterangepicker table { + width: 100%; + margin: 0; } + .daterangepicker td, .daterangepicker th { + text-align: center; + width: 20px; + height: 20px; + border-radius: 4px; + border: 1px solid transparent; + white-space: nowrap; + cursor: pointer; } + .daterangepicker td.available:hover, .daterangepicker th.available:hover { + background-color: #eee; + border-color: transparent; + color: inherit; } + .daterangepicker td.week, .daterangepicker th.week { + font-size: 80%; + color: #ccc; } + .daterangepicker td.off, .daterangepicker td.off.in-range, .daterangepicker td.off.start-date, .daterangepicker td.off.end-date { + background-color: #fff; + border-color: transparent; + color: #999; } + .daterangepicker td.in-range { + background-color: #ebf4f8; + border-color: transparent; + color: #000; + border-radius: 0; } + .daterangepicker td.start-date { + border-radius: 4px 0 0 4px; } + .daterangepicker td.end-date { + border-radius: 0 4px 4px 0; } + .daterangepicker td.start-date.end-date { + border-radius: 4px; } + .daterangepicker td.active, .daterangepicker td.active:hover { + background-color: #357ebd; + border-color: transparent; + color: #fff; } + .daterangepicker th.month { + width: auto; } + .daterangepicker td.disabled, .daterangepicker option.disabled { + color: #999; + cursor: not-allowed; + text-decoration: line-through; } + .daterangepicker select.monthselect, .daterangepicker select.yearselect { + font-size: 12px; + padding: 1px; + height: auto; + margin: 0; + cursor: default; } + .daterangepicker select.monthselect { + margin-right: 2%; + width: 56%; } + .daterangepicker select.yearselect { + width: 40%; } + .daterangepicker select.hourselect, .daterangepicker select.minuteselect, .daterangepicker select.secondselect, .daterangepicker select.ampmselect { + width: 50px; + margin-bottom: 0; } + .daterangepicker .input-mini { + border: 1px solid #ccc; + border-radius: 4px; + color: #555; + height: 30px; + line-height: 30px; + display: block; + vertical-align: middle; + margin: 0 0 5px 0; + padding: 0 6px 0 28px; + width: 100%; } + .daterangepicker .input-mini.active { + border: 1px solid #08c; + border-radius: 4px; } + .daterangepicker .daterangepicker_input { + position: relative; } + .daterangepicker .daterangepicker_input i { + position: absolute; + left: 8px; + top: 8px; } + .daterangepicker.rtl .input-mini { + padding-right: 28px; + padding-left: 6px; } + .daterangepicker.rtl .daterangepicker_input i { + left: auto; + right: 8px; } + .daterangepicker .calendar-time { + text-align: center; + margin: 5px auto; + line-height: 30px; + position: relative; + padding-left: 28px; } + .daterangepicker .calendar-time select.disabled { + color: #ccc; + cursor: not-allowed; } + +.ranges { + font-size: 11px; + float: none; + margin: 4px; + text-align: left; } + .ranges ul { + list-style: none; + margin: 0 auto; + padding: 0; + width: 100%; } + .ranges li { + font-size: 13px; + background-color: #f5f5f5; + border: 1px solid #f5f5f5; + border-radius: 4px; + color: #08c; + padding: 3px 12px; + margin-bottom: 8px; + cursor: pointer; } + .ranges li:hover { + background-color: #08c; + border: 1px solid #08c; + color: #fff; } + .ranges li.active { + background-color: #08c; + border: 1px solid #08c; + color: #fff; } + +/* Larger Screen Styling */ +@media (min-width: 564px) { + .daterangepicker { + width: auto; } + .daterangepicker .ranges ul { + width: 160px; } + .daterangepicker.single .ranges ul { + width: 100%; } + .daterangepicker.single .calendar.left { + clear: none; } + .daterangepicker.single.ltr .ranges, .daterangepicker.single.ltr .calendar { + float: left; } + .daterangepicker.single.rtl .ranges, .daterangepicker.single.rtl .calendar { + float: right; } + .daterangepicker.ltr { + direction: ltr; + text-align: left; } + .daterangepicker.ltr .calendar.left { + clear: left; + margin-right: 0; } + .daterangepicker.ltr .calendar.left .calendar-table { + border-right: none; + border-top-right-radius: 0; + border-bottom-right-radius: 0; } + .daterangepicker.ltr .calendar.right { + margin-left: 0; } + .daterangepicker.ltr .calendar.right .calendar-table { + border-left: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; } + .daterangepicker.ltr .left .daterangepicker_input { + padding-right: 12px; } + .daterangepicker.ltr .calendar.left .calendar-table { + padding-right: 12px; } + .daterangepicker.ltr .ranges, .daterangepicker.ltr .calendar { + float: left; } + .daterangepicker.rtl { + direction: rtl; + text-align: right; } + .daterangepicker.rtl .calendar.left { + clear: right; + margin-left: 0; } + .daterangepicker.rtl .calendar.left .calendar-table { + border-left: none; + border-top-left-radius: 0; + border-bottom-left-radius: 0; } + .daterangepicker.rtl .calendar.right { + margin-right: 0; } + .daterangepicker.rtl .calendar.right .calendar-table { + border-right: none; + border-top-right-radius: 0; + border-bottom-right-radius: 0; } + .daterangepicker.rtl .left .daterangepicker_input { + padding-left: 12px; } + .daterangepicker.rtl .calendar.left .calendar-table { + padding-left: 12px; } + .daterangepicker.rtl .ranges, .daterangepicker.rtl .calendar { + text-align: right; + float: right; } } +@media (min-width: 730px) { + .daterangepicker .ranges { + width: auto; } + .daterangepicker.ltr .ranges { + float: left; } + .daterangepicker.rtl .ranges { + float: right; } + .daterangepicker .calendar.left { + clear: none !important; } } diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js new file mode 100644 index 0000000..079cde6 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js @@ -0,0 +1,1653 @@ +/** +* @version: 2.1.27 +* @author: Dan Grossman http://www.dangrossman.info/ +* @copyright: Copyright (c) 2012-2017 Dan Grossman. All rights reserved. +* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php +* @website: http://www.daterangepicker.com/ +*/ +// Follow the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Make globaly available as well + define(['moment', 'jquery'], function (moment, jquery) { + if (!jquery.fn) jquery.fn = {}; // webpack server rendering + return factory(moment, jquery); + }); + } else if (typeof module === 'object' && module.exports) { + // Node / Browserify + //isomorphic issue + var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined; + if (!jQuery) { + jQuery = require('jquery'); + if (!jQuery.fn) jQuery.fn = {}; + } + var moment = (typeof window != 'undefined' && typeof window.moment != 'undefined') ? window.moment : require('moment'); + module.exports = factory(moment, jQuery); + } else { + // Browser globals + root.daterangepicker = factory(root.moment, root.jQuery); + } +}(this, function(moment, $) { + var DateRangePicker = function(element, options, cb) { + + //default settings for options + this.parentEl = 'body'; + this.element = $(element); + this.startDate = moment().startOf('day'); + this.endDate = moment().endOf('day'); + this.minDate = false; + this.maxDate = false; + this.dateLimit = false; + this.autoApply = false; + this.singleDatePicker = false; + this.showDropdowns = false; + this.showWeekNumbers = false; + this.showISOWeekNumbers = false; + this.showCustomRangeLabel = true; + this.timePicker = false; + this.timePicker24Hour = false; + this.timePickerIncrement = 1; + this.timePickerSeconds = false; + this.linkedCalendars = true; + this.autoUpdateInput = true; + this.alwaysShowCalendars = false; + this.ranges = {}; + + this.opens = 'right'; + if (this.element.hasClass('pull-right')) + this.opens = 'left'; + + this.drops = 'down'; + if (this.element.hasClass('dropup')) + this.drops = 'up'; + + this.buttonClasses = 'btn btn-sm'; + this.applyClass = 'btn-success'; + this.cancelClass = 'btn-default'; + + this.locale = { + direction: 'ltr', + format: moment.localeData().longDateFormat('L'), + separator: ' - ', + applyLabel: 'Apply', + cancelLabel: 'Cancel', + weekLabel: 'W', + customRangeLabel: 'Custom Range', + daysOfWeek: moment.weekdaysMin(), + monthNames: moment.monthsShort(), + firstDay: moment.localeData().firstDayOfWeek() + }; + + this.callback = function() { }; + + //some state information + this.isShowing = false; + this.leftCalendar = {}; + this.rightCalendar = {}; + + //custom options from user + if (typeof options !== 'object' || options === null) + options = {}; + + //allow setting options with data attributes + //data-api options will be overwritten with custom javascript options + options = $.extend(this.element.data(), options); + + //html template for the picker UI + if (typeof options.template !== 'string' && !(options.template instanceof $)) + options.template = ''; + + this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); + this.container = $(options.template).appendTo(this.parentEl); + + // + // handle all the possible options overriding defaults + // + + if (typeof options.locale === 'object') { + + if (typeof options.locale.direction === 'string') + this.locale.direction = options.locale.direction; + + if (typeof options.locale.format === 'string') + this.locale.format = options.locale.format; + + if (typeof options.locale.separator === 'string') + this.locale.separator = options.locale.separator; + + if (typeof options.locale.daysOfWeek === 'object') + this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); + + if (typeof options.locale.monthNames === 'object') + this.locale.monthNames = options.locale.monthNames.slice(); + + if (typeof options.locale.firstDay === 'number') + this.locale.firstDay = options.locale.firstDay; + + if (typeof options.locale.applyLabel === 'string') + this.locale.applyLabel = options.locale.applyLabel; + + if (typeof options.locale.cancelLabel === 'string') + this.locale.cancelLabel = options.locale.cancelLabel; + + if (typeof options.locale.weekLabel === 'string') + this.locale.weekLabel = options.locale.weekLabel; + + if (typeof options.locale.customRangeLabel === 'string'){ + //Support unicode chars in the custom range name. + var elem = document.createElement('textarea'); + elem.innerHTML = options.locale.customRangeLabel; + var rangeHtml = elem.value; + this.locale.customRangeLabel = rangeHtml; + } + } + this.container.addClass(this.locale.direction); + + if (typeof options.startDate === 'string') + this.startDate = moment(options.startDate, this.locale.format); + + if (typeof options.endDate === 'string') + this.endDate = moment(options.endDate, this.locale.format); + + if (typeof options.minDate === 'string') + this.minDate = moment(options.minDate, this.locale.format); + + if (typeof options.maxDate === 'string') + this.maxDate = moment(options.maxDate, this.locale.format); + + if (typeof options.startDate === 'object') + this.startDate = moment(options.startDate); + + if (typeof options.endDate === 'object') + this.endDate = moment(options.endDate); + + if (typeof options.minDate === 'object') + this.minDate = moment(options.minDate); + + if (typeof options.maxDate === 'object') + this.maxDate = moment(options.maxDate); + + // sanity check for bad options + if (this.minDate && this.startDate.isBefore(this.minDate)) + this.startDate = this.minDate.clone(); + + // sanity check for bad options + if (this.maxDate && this.endDate.isAfter(this.maxDate)) + this.endDate = this.maxDate.clone(); + + if (typeof options.applyClass === 'string') + this.applyClass = options.applyClass; + + if (typeof options.cancelClass === 'string') + this.cancelClass = options.cancelClass; + + if (typeof options.dateLimit === 'object') + this.dateLimit = options.dateLimit; + + if (typeof options.opens === 'string') + this.opens = options.opens; + + if (typeof options.drops === 'string') + this.drops = options.drops; + + if (typeof options.showWeekNumbers === 'boolean') + this.showWeekNumbers = options.showWeekNumbers; + + if (typeof options.showISOWeekNumbers === 'boolean') + this.showISOWeekNumbers = options.showISOWeekNumbers; + + if (typeof options.buttonClasses === 'string') + this.buttonClasses = options.buttonClasses; + + if (typeof options.buttonClasses === 'object') + this.buttonClasses = options.buttonClasses.join(' '); + + if (typeof options.showDropdowns === 'boolean') + this.showDropdowns = options.showDropdowns; + + if (typeof options.showCustomRangeLabel === 'boolean') + this.showCustomRangeLabel = options.showCustomRangeLabel; + + if (typeof options.singleDatePicker === 'boolean') { + this.singleDatePicker = options.singleDatePicker; + if (this.singleDatePicker) + this.endDate = this.startDate.clone(); + } + + if (typeof options.timePicker === 'boolean') + this.timePicker = options.timePicker; + + if (typeof options.timePickerSeconds === 'boolean') + this.timePickerSeconds = options.timePickerSeconds; + + if (typeof options.timePickerIncrement === 'number') + this.timePickerIncrement = options.timePickerIncrement; + + if (typeof options.timePicker24Hour === 'boolean') + this.timePicker24Hour = options.timePicker24Hour; + + if (typeof options.autoApply === 'boolean') + this.autoApply = options.autoApply; + + if (typeof options.autoUpdateInput === 'boolean') + this.autoUpdateInput = options.autoUpdateInput; + + if (typeof options.linkedCalendars === 'boolean') + this.linkedCalendars = options.linkedCalendars; + + if (typeof options.isInvalidDate === 'function') + this.isInvalidDate = options.isInvalidDate; + + if (typeof options.isCustomDate === 'function') + this.isCustomDate = options.isCustomDate; + + if (typeof options.alwaysShowCalendars === 'boolean') + this.alwaysShowCalendars = options.alwaysShowCalendars; + + // update day names order to firstDay + if (this.locale.firstDay != 0) { + var iterator = this.locale.firstDay; + while (iterator > 0) { + this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); + iterator--; + } + } + + var start, end, range; + + //if no start/end dates set, check if an input element contains initial values + if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { + if ($(this.element).is('input[type=text]')) { + var val = $(this.element).val(), + split = val.split(this.locale.separator); + + start = end = null; + + if (split.length == 2) { + start = moment(split[0], this.locale.format); + end = moment(split[1], this.locale.format); + } else if (this.singleDatePicker && val !== "") { + start = moment(val, this.locale.format); + end = moment(val, this.locale.format); + } + if (start !== null && end !== null) { + this.setStartDate(start); + this.setEndDate(end); + } + } + } + + if (typeof options.ranges === 'object') { + for (range in options.ranges) { + + if (typeof options.ranges[range][0] === 'string') + start = moment(options.ranges[range][0], this.locale.format); + else + start = moment(options.ranges[range][0]); + + if (typeof options.ranges[range][1] === 'string') + end = moment(options.ranges[range][1], this.locale.format); + else + end = moment(options.ranges[range][1]); + + // If the start or end date exceed those allowed by the minDate or dateLimit + // options, shorten the range to the allowable period. + if (this.minDate && start.isBefore(this.minDate)) + start = this.minDate.clone(); + + var maxDate = this.maxDate; + if (this.dateLimit && maxDate && start.clone().add(this.dateLimit).isAfter(maxDate)) + maxDate = start.clone().add(this.dateLimit); + if (maxDate && end.isAfter(maxDate)) + end = maxDate.clone(); + + // If the end of the range is before the minimum or the start of the range is + // after the maximum, don't display this range option at all. + if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) + || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day'))) + continue; + + //Support unicode chars in the range names. + var elem = document.createElement('textarea'); + elem.innerHTML = range; + var rangeHtml = elem.value; + + this.ranges[rangeHtml] = [start, end]; + } + + var list = '
    '; + for (range in this.ranges) { + list += '
  • ' + range + '
  • '; + } + if (this.showCustomRangeLabel) { + list += '
  • ' + this.locale.customRangeLabel + '
  • '; + } + list += '
'; + this.container.find('.ranges').prepend(list); + } + + if (typeof cb === 'function') { + this.callback = cb; + } + + if (!this.timePicker) { + this.startDate = this.startDate.startOf('day'); + this.endDate = this.endDate.endOf('day'); + this.container.find('.calendar-time').hide(); + } + + //can't be used together for now + if (this.timePicker && this.autoApply) + this.autoApply = false; + + if (this.autoApply && typeof options.ranges !== 'object') { + this.container.find('.ranges').hide(); + } else if (this.autoApply) { + this.container.find('.applyBtn, .cancelBtn').addClass('hide'); + } + + if (this.singleDatePicker) { + this.container.addClass('single'); + this.container.find('.calendar.left').addClass('single'); + this.container.find('.calendar.left').show(); + this.container.find('.calendar.right').hide(); + this.container.find('.daterangepicker_input input, .daterangepicker_input > i').hide(); + if (this.timePicker) { + this.container.find('.ranges ul').hide(); + } else { + this.container.find('.ranges').hide(); + } + } + + if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) { + this.container.addClass('show-calendar'); + } + + this.container.addClass('opens' + this.opens); + + //swap the position of the predefined ranges if opens right + if (typeof options.ranges !== 'undefined' && this.opens == 'right') { + this.container.find('.ranges').prependTo( this.container.find('.calendar.left').parent() ); + } + + //apply CSS classes and labels to buttons + this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses); + if (this.applyClass.length) + this.container.find('.applyBtn').addClass(this.applyClass); + if (this.cancelClass.length) + this.container.find('.cancelBtn').addClass(this.cancelClass); + this.container.find('.applyBtn').html(this.locale.applyLabel); + this.container.find('.cancelBtn').html(this.locale.cancelLabel); + + // + // event listeners + // + + this.container.find('.calendar') + .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)) + .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)) + .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this)) + .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)) + .on('mouseleave.daterangepicker', 'td.available', $.proxy(this.updateFormInputs, this)) + .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this)) + .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this)) + .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this)) + .on('click.daterangepicker', '.daterangepicker_input input', $.proxy(this.showCalendars, this)) + .on('focus.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsFocused, this)) + .on('blur.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsBlurred, this)) + .on('change.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsChanged, this)) + .on('keydown.daterangepicker', '.daterangepicker_input input', $.proxy(this.formInputsKeydown, this)); + + this.container.find('.ranges') + .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)) + .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)) + .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)) + .on('mouseenter.daterangepicker', 'li', $.proxy(this.hoverRange, this)) + .on('mouseleave.daterangepicker', 'li', $.proxy(this.updateFormInputs, this)); + + if (this.element.is('input') || this.element.is('button')) { + this.element.on({ + 'click.daterangepicker': $.proxy(this.show, this), + 'focus.daterangepicker': $.proxy(this.show, this), + 'keyup.daterangepicker': $.proxy(this.elementChanged, this), + 'keydown.daterangepicker': $.proxy(this.keydown, this) //IE 11 compatibility + }); + } else { + this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); + this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this)); + } + + // + // if attached to a text input, set the initial value + // + + if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); + this.element.trigger('change'); + } else if (this.element.is('input') && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format)); + this.element.trigger('change'); + } + + }; + + DateRangePicker.prototype = { + + constructor: DateRangePicker, + + setStartDate: function(startDate) { + if (typeof startDate === 'string') + this.startDate = moment(startDate, this.locale.format); + + if (typeof startDate === 'object') + this.startDate = moment(startDate); + + if (!this.timePicker) + this.startDate = this.startDate.startOf('day'); + + if (this.timePicker && this.timePickerIncrement) + this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); + + if (this.minDate && this.startDate.isBefore(this.minDate)) { + this.startDate = this.minDate.clone(); + if (this.timePicker && this.timePickerIncrement) + this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); + } + + if (this.maxDate && this.startDate.isAfter(this.maxDate)) { + this.startDate = this.maxDate.clone(); + if (this.timePicker && this.timePickerIncrement) + this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); + } + + if (!this.isShowing) + this.updateElement(); + + this.updateMonthsInView(); + }, + + setEndDate: function(endDate) { + if (typeof endDate === 'string') + this.endDate = moment(endDate, this.locale.format); + + if (typeof endDate === 'object') + this.endDate = moment(endDate); + + if (!this.timePicker) + this.endDate = this.endDate.add(1,'d').startOf('day').subtract(1,'second'); + + if (this.timePicker && this.timePickerIncrement) + this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); + + if (this.endDate.isBefore(this.startDate)) + this.endDate = this.startDate.clone(); + + if (this.maxDate && this.endDate.isAfter(this.maxDate)) + this.endDate = this.maxDate.clone(); + + if (this.dateLimit && this.startDate.clone().add(this.dateLimit).isBefore(this.endDate)) + this.endDate = this.startDate.clone().add(this.dateLimit); + + this.previousRightTime = this.endDate.clone(); + + if (!this.isShowing) + this.updateElement(); + + this.updateMonthsInView(); + }, + + isInvalidDate: function() { + return false; + }, + + isCustomDate: function() { + return false; + }, + + updateView: function() { + if (this.timePicker) { + this.renderTimePicker('left'); + this.renderTimePicker('right'); + if (!this.endDate) { + this.container.find('.right .calendar-time select').attr('disabled', 'disabled').addClass('disabled'); + } else { + this.container.find('.right .calendar-time select').removeAttr('disabled').removeClass('disabled'); + } + } + if (this.endDate) { + this.container.find('input[name="daterangepicker_end"]').removeClass('active'); + this.container.find('input[name="daterangepicker_start"]').addClass('active'); + } else { + this.container.find('input[name="daterangepicker_end"]').addClass('active'); + this.container.find('input[name="daterangepicker_start"]').removeClass('active'); + } + this.updateMonthsInView(); + this.updateCalendars(); + this.updateFormInputs(); + }, + + updateMonthsInView: function() { + if (this.endDate) { + + //if both dates are visible already, do nothing + if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month && + (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) + && + (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) + ) { + return; + } + + this.leftCalendar.month = this.startDate.clone().date(2); + if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) { + this.rightCalendar.month = this.endDate.clone().date(2); + } else { + this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); + } + + } else { + if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) { + this.leftCalendar.month = this.startDate.clone().date(2); + this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); + } + } + if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) { + this.rightCalendar.month = this.maxDate.clone().date(2); + this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month'); + } + }, + + updateCalendars: function() { + + if (this.timePicker) { + var hour, minute, second; + if (this.endDate) { + hour = parseInt(this.container.find('.left .hourselect').val(), 10); + minute = parseInt(this.container.find('.left .minuteselect').val(), 10); + second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; + if (!this.timePicker24Hour) { + var ampm = this.container.find('.left .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + } else { + hour = parseInt(this.container.find('.right .hourselect').val(), 10); + minute = parseInt(this.container.find('.right .minuteselect').val(), 10); + second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; + if (!this.timePicker24Hour) { + var ampm = this.container.find('.right .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + } + this.leftCalendar.month.hour(hour).minute(minute).second(second); + this.rightCalendar.month.hour(hour).minute(minute).second(second); + } + + this.renderCalendar('left'); + this.renderCalendar('right'); + + //highlight any predefined range matching the current start and end dates + this.container.find('.ranges li').removeClass('active'); + if (this.endDate == null) return; + + this.calculateChosenLabel(); + }, + + renderCalendar: function(side) { + + // + // Build the matrix of dates that will populate the calendar + // + + var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar; + var month = calendar.month.month(); + var year = calendar.month.year(); + var hour = calendar.month.hour(); + var minute = calendar.month.minute(); + var second = calendar.month.second(); + var daysInMonth = moment([year, month]).daysInMonth(); + var firstDay = moment([year, month, 1]); + var lastDay = moment([year, month, daysInMonth]); + var lastMonth = moment(firstDay).subtract(1, 'month').month(); + var lastYear = moment(firstDay).subtract(1, 'month').year(); + var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); + var dayOfWeek = firstDay.day(); + + //initialize a 6 rows x 7 columns array for the calendar + var calendar = []; + calendar.firstDay = firstDay; + calendar.lastDay = lastDay; + + for (var i = 0; i < 6; i++) { + calendar[i] = []; + } + + //populate the calendar with date objects + var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; + if (startDay > daysInLastMonth) + startDay -= 7; + + if (dayOfWeek == this.locale.firstDay) + startDay = daysInLastMonth - 6; + + var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]); + + var col, row; + for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { + if (i > 0 && col % 7 === 0) { + col = 0; + row++; + } + calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second); + curDate.hour(12); + + if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { + calendar[row][col] = this.minDate.clone(); + } + + if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { + calendar[row][col] = this.maxDate.clone(); + } + + } + + //make the calendar object available to hoverDate/clickDate + if (side == 'left') { + this.leftCalendar.calendar = calendar; + } else { + this.rightCalendar.calendar = calendar; + } + + // + // Display the calendar + // + + var minDate = side == 'left' ? this.minDate : this.startDate; + var maxDate = this.maxDate; + var selected = side == 'left' ? this.startDate : this.endDate; + var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'}; + + var html = ''; + html += ''; + html += ''; + + // add empty cell for week number + if (this.showWeekNumbers || this.showISOWeekNumbers) + html += ''; + + if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || side == 'left')) { + html += ''; + } else { + html += ''; + } + + var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); + + if (this.showDropdowns) { + var currentMonth = calendar[1][1].month(); + var currentYear = calendar[1][1].year(); + var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); + var minYear = (minDate && minDate.year()) || (currentYear - 50); + var inMinYear = currentYear == minYear; + var inMaxYear = currentYear == maxYear; + + var monthHtml = '"; + + var yearHtml = ''; + + dateHtml = monthHtml + yearHtml; + } + + html += ''; + if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker)) { + html += ''; + } else { + html += ''; + } + + html += ''; + html += ''; + + // add week number label + if (this.showWeekNumbers || this.showISOWeekNumbers) + html += ''; + + $.each(this.locale.daysOfWeek, function(index, dayOfWeek) { + html += ''; + }); + + html += ''; + html += ''; + html += ''; + + //adjust maxDate to reflect the dateLimit setting in order to + //grey out end dates beyond the dateLimit + if (this.endDate == null && this.dateLimit) { + var maxLimit = this.startDate.clone().add(this.dateLimit).endOf('day'); + if (!maxDate || maxLimit.isBefore(maxDate)) { + maxDate = maxLimit; + } + } + + for (var row = 0; row < 6; row++) { + html += ''; + + // add week number + if (this.showWeekNumbers) + html += ''; + else if (this.showISOWeekNumbers) + html += ''; + + for (var col = 0; col < 7; col++) { + + var classes = []; + + //highlight today's date + if (calendar[row][col].isSame(new Date(), "day")) + classes.push('today'); + + //highlight weekends + if (calendar[row][col].isoWeekday() > 5) + classes.push('weekend'); + + //grey out the dates in other months displayed at beginning and end of this calendar + if (calendar[row][col].month() != calendar[1][1].month()) + classes.push('off'); + + //don't allow selection of dates before the minimum date + if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day')) + classes.push('off', 'disabled'); + + //don't allow selection of dates after the maximum date + if (maxDate && calendar[row][col].isAfter(maxDate, 'day')) + classes.push('off', 'disabled'); + + //don't allow selection of date if a custom function decides it's invalid + if (this.isInvalidDate(calendar[row][col])) + classes.push('off', 'disabled'); + + //highlight the currently selected start date + if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) + classes.push('active', 'start-date'); + + //highlight the currently selected end date + if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) + classes.push('active', 'end-date'); + + //highlight dates in-between the selected dates + if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate) + classes.push('in-range'); + + //apply custom classes for this date + var isCustom = this.isCustomDate(calendar[row][col]); + if (isCustom !== false) { + if (typeof isCustom === 'string') + classes.push(isCustom); + else + Array.prototype.push.apply(classes, isCustom); + } + + var cname = '', disabled = false; + for (var i = 0; i < classes.length; i++) { + cname += classes[i] + ' '; + if (classes[i] == 'disabled') + disabled = true; + } + if (!disabled) + cname += 'available'; + + html += ''; + + } + html += ''; + } + + html += ''; + html += '
' + dateHtml + '
' + this.locale.weekLabel + '' + dayOfWeek + '
' + calendar[row][0].week() + '' + calendar[row][0].isoWeek() + '' + calendar[row][col].date() + '
'; + + this.container.find('.calendar.' + side + ' .calendar-table').html(html); + + }, + + renderTimePicker: function(side) { + + // Don't bother updating the time picker if it's currently disabled + // because an end date hasn't been clicked yet + if (side == 'right' && !this.endDate) return; + + var html, selected, minDate, maxDate = this.maxDate; + + if (this.dateLimit && (!this.maxDate || this.startDate.clone().add(this.dateLimit).isAfter(this.maxDate))) + maxDate = this.startDate.clone().add(this.dateLimit); + + if (side == 'left') { + selected = this.startDate.clone(); + minDate = this.minDate; + } else if (side == 'right') { + selected = this.endDate.clone(); + minDate = this.startDate; + + //Preserve the time already selected + var timeSelector = this.container.find('.calendar.right .calendar-time div'); + if (timeSelector.html() != '') { + + selected.hour(timeSelector.find('.hourselect option:selected').val() || selected.hour()); + selected.minute(timeSelector.find('.minuteselect option:selected').val() || selected.minute()); + selected.second(timeSelector.find('.secondselect option:selected').val() || selected.second()); + + if (!this.timePicker24Hour) { + var ampm = timeSelector.find('.ampmselect option:selected').val(); + if (ampm === 'PM' && selected.hour() < 12) + selected.hour(selected.hour() + 12); + if (ampm === 'AM' && selected.hour() === 12) + selected.hour(0); + } + + } + + if (selected.isBefore(this.startDate)) + selected = this.startDate.clone(); + + if (maxDate && selected.isAfter(maxDate)) + selected = maxDate.clone(); + + } + + // + // hours + // + + html = ' '; + + // + // minutes + // + + html += ': '; + + // + // seconds + // + + if (this.timePickerSeconds) { + html += ': '; + } + + // + // AM/PM + // + + if (!this.timePicker24Hour) { + html += ''; + } + + this.container.find('.calendar.' + side + ' .calendar-time div').html(html); + + }, + + updateFormInputs: function() { + + //ignore mouse movements while an above-calendar text input has focus + if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + return; + + this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.locale.format)); + if (this.endDate) + this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.locale.format)); + + if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) { + this.container.find('button.applyBtn').removeAttr('disabled'); + } else { + this.container.find('button.applyBtn').attr('disabled', 'disabled'); + } + + }, + + move: function() { + var parentOffset = { top: 0, left: 0 }, + containerTop; + var parentRightEdge = $(window).width(); + if (!this.parentEl.is('body')) { + parentOffset = { + top: this.parentEl.offset().top - this.parentEl.scrollTop(), + left: this.parentEl.offset().left - this.parentEl.scrollLeft() + }; + parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; + } + + if (this.drops == 'up') + containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; + else + containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; + this.container[this.drops == 'up' ? 'addClass' : 'removeClass']('dropup'); + + if (this.opens == 'left') { + this.container.css({ + top: containerTop, + right: parentRightEdge - this.element.offset().left - this.element.outerWidth(), + left: 'auto' + }); + if (this.container.offset().left < 0) { + this.container.css({ + right: 'auto', + left: 9 + }); + } + } else if (this.opens == 'center') { + this.container.css({ + top: containerTop, + left: this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 + - this.container.outerWidth() / 2, + right: 'auto' + }); + if (this.container.offset().left < 0) { + this.container.css({ + right: 'auto', + left: 9 + }); + } + } else { + this.container.css({ + top: containerTop, + left: this.element.offset().left - parentOffset.left, + right: 'auto' + }); + if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { + this.container.css({ + left: 'auto', + right: 0 + }); + } + } + }, + + show: function(e) { + if (this.isShowing) return; + + // Create a click proxy that is private to this instance of datepicker, for unbinding + this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this); + + // Bind global datepicker mousedown for hiding and + $(document) + .on('mousedown.daterangepicker', this._outsideClickProxy) + // also support mobile devices + .on('touchend.daterangepicker', this._outsideClickProxy) + // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them + .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy) + // and also close when focus changes to outside the picker (eg. tabbing between controls) + .on('focusin.daterangepicker', this._outsideClickProxy); + + // Reposition the picker if the window is resized while it's open + $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this)); + + this.oldStartDate = this.startDate.clone(); + this.oldEndDate = this.endDate.clone(); + this.previousRightTime = this.endDate.clone(); + + this.updateView(); + this.container.show(); + this.move(); + this.element.trigger('show.daterangepicker', this); + this.isShowing = true; + }, + + hide: function(e) { + if (!this.isShowing) return; + + //incomplete date selection, revert to last values + if (!this.endDate) { + this.startDate = this.oldStartDate.clone(); + this.endDate = this.oldEndDate.clone(); + } + + //if a new date range was selected, invoke the user callback function + if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) + this.callback(this.startDate, this.endDate, this.chosenLabel); + + //if picker is attached to a text input, update it + this.updateElement(); + + $(document).off('.daterangepicker'); + $(window).off('.daterangepicker'); + this.container.hide(); + this.element.trigger('hide.daterangepicker', this); + this.isShowing = false; + }, + + toggle: function(e) { + if (this.isShowing) { + this.hide(); + } else { + this.show(); + } + }, + + outsideClick: function(e) { + var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button + // itself then call this.hide() + if ( + // ie modal dialog fix + e.type == "focusin" || + target.closest(this.element).length || + target.closest(this.container).length || + target.closest('.calendar-table').length + ) return; + this.hide(); + this.element.trigger('outsideClick.daterangepicker', this); + }, + + showCalendars: function() { + this.container.addClass('show-calendar'); + this.move(); + this.element.trigger('showCalendar.daterangepicker', this); + }, + + hideCalendars: function() { + this.container.removeClass('show-calendar'); + this.element.trigger('hideCalendar.daterangepicker', this); + }, + + hoverRange: function(e) { + + //ignore mouse movements while an above-calendar text input has focus + if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + return; + + var label = e.target.getAttribute('data-range-key'); + + if (label == this.locale.customRangeLabel) { + this.updateView(); + } else { + var dates = this.ranges[label]; + this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.locale.format)); + this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.locale.format)); + } + + }, + + clickRange: function(e) { + var label = e.target.getAttribute('data-range-key'); + this.chosenLabel = label; + if (label == this.locale.customRangeLabel) { + this.showCalendars(); + } else { + var dates = this.ranges[label]; + this.startDate = dates[0]; + this.endDate = dates[1]; + + if (!this.timePicker) { + this.startDate.startOf('day'); + this.endDate.endOf('day'); + } + + if (!this.alwaysShowCalendars) + this.hideCalendars(); + this.clickApply(); + } + }, + + clickPrev: function(e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.subtract(1, 'month'); + if (this.linkedCalendars) + this.rightCalendar.month.subtract(1, 'month'); + } else { + this.rightCalendar.month.subtract(1, 'month'); + } + this.updateCalendars(); + }, + + clickNext: function(e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.add(1, 'month'); + } else { + this.rightCalendar.month.add(1, 'month'); + if (this.linkedCalendars) + this.leftCalendar.month.add(1, 'month'); + } + this.updateCalendars(); + }, + + hoverDate: function(e) { + + //ignore mouse movements while an above-calendar text input has focus + //if (this.container.find('input[name=daterangepicker_start]').is(":focus") || this.container.find('input[name=daterangepicker_end]').is(":focus")) + // return; + + //ignore dates that can't be selected + if (!$(e.target).hasClass('available')) return; + + //have the text inputs above calendars reflect the date being hovered over + var title = $(e.target).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + + if (this.endDate && !this.container.find('input[name=daterangepicker_start]').is(":focus")) { + this.container.find('input[name=daterangepicker_start]').val(date.format(this.locale.format)); + } else if (!this.endDate && !this.container.find('input[name=daterangepicker_end]').is(":focus")) { + this.container.find('input[name=daterangepicker_end]').val(date.format(this.locale.format)); + } + + //highlight the dates between the start date and the date being hovered as a potential end date + var leftCalendar = this.leftCalendar; + var rightCalendar = this.rightCalendar; + var startDate = this.startDate; + if (!this.endDate) { + this.container.find('.calendar tbody td').each(function(index, el) { + + //skip week numbers, only look at dates + if ($(el).hasClass('week')) return; + + var title = $(el).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(el).parents('.calendar'); + var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col]; + + if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) { + $(el).addClass('in-range'); + } else { + $(el).removeClass('in-range'); + } + + }); + } + + }, + + clickDate: function(e) { + + if (!$(e.target).hasClass('available')) return; + + var title = $(e.target).attr('data-title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; + + // + // this function needs to do a few things: + // * alternate between selecting a start and end date for the range, + // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date + // * if autoapply is enabled, and an end date was chosen, apply the selection + // * if single date picker mode, and time picker isn't enabled, apply the selection immediately + // * if one of the inputs above the calendars was focused, cancel that manual input + // + + if (this.endDate || date.isBefore(this.startDate, 'day')) { //picking start + if (this.timePicker) { + var hour = parseInt(this.container.find('.left .hourselect').val(), 10); + if (!this.timePicker24Hour) { + var ampm = this.container.find('.left .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + var minute = parseInt(this.container.find('.left .minuteselect').val(), 10); + var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; + date = date.clone().hour(hour).minute(minute).second(second); + } + this.endDate = null; + this.setStartDate(date.clone()); + } else if (!this.endDate && date.isBefore(this.startDate)) { + //special case: clicking the same date for start/end, + //but the time of the end date is before the start date + this.setEndDate(this.startDate.clone()); + } else { // picking end + if (this.timePicker) { + var hour = parseInt(this.container.find('.right .hourselect').val(), 10); + if (!this.timePicker24Hour) { + var ampm = this.container.find('.right .ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + var minute = parseInt(this.container.find('.right .minuteselect').val(), 10); + var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; + date = date.clone().hour(hour).minute(minute).second(second); + } + this.setEndDate(date.clone()); + if (this.autoApply) { + this.calculateChosenLabel(); + this.clickApply(); + } + } + + if (this.singleDatePicker) { + this.setEndDate(this.startDate); + if (!this.timePicker) + this.clickApply(); + } + + this.updateView(); + + //This is to cancel the blur event handler if the mouse was in one of the inputs + e.stopPropagation(); + + }, + + calculateChosenLabel: function () { + var customRange = true; + var i = 0; + for (var range in this.ranges) { + if (this.timePicker) { + var format = this.timePickerSeconds ? "YYYY-MM-DD hh:mm:ss" : "YYYY-MM-DD hh:mm"; + //ignore times when comparing dates if time picker seconds is not enabled + if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) { + customRange = false; + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html(); + break; + } + } else { + //ignore times when comparing dates if time picker is not enabled + if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { + customRange = false; + this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').html(); + break; + } + } + i++; + } + if (customRange) { + if (this.showCustomRangeLabel) { + this.chosenLabel = this.container.find('.ranges li:last').addClass('active').html(); + } else { + this.chosenLabel = null; + } + this.showCalendars(); + } + }, + + clickApply: function(e) { + this.hide(); + this.element.trigger('apply.daterangepicker', this); + }, + + clickCancel: function(e) { + this.startDate = this.oldStartDate; + this.endDate = this.oldEndDate; + this.hide(); + this.element.trigger('cancel.daterangepicker', this); + }, + + monthOrYearChanged: function(e) { + var isLeft = $(e.target).closest('.calendar').hasClass('left'), + leftOrRight = isLeft ? 'left' : 'right', + cal = this.container.find('.calendar.'+leftOrRight); + + // Month must be Number for new moment versions + var month = parseInt(cal.find('.monthselect').val(), 10); + var year = cal.find('.yearselect').val(); + + if (!isLeft) { + if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) { + month = this.startDate.month(); + year = this.startDate.year(); + } + } + + if (this.minDate) { + if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) { + month = this.minDate.month(); + year = this.minDate.year(); + } + } + + if (this.maxDate) { + if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) { + month = this.maxDate.month(); + year = this.maxDate.year(); + } + } + + if (isLeft) { + this.leftCalendar.month.month(month).year(year); + if (this.linkedCalendars) + this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month'); + } else { + this.rightCalendar.month.month(month).year(year); + if (this.linkedCalendars) + this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month'); + } + this.updateCalendars(); + }, + + timeChanged: function(e) { + + var cal = $(e.target).closest('.calendar'), + isLeft = cal.hasClass('left'); + + var hour = parseInt(cal.find('.hourselect').val(), 10); + var minute = parseInt(cal.find('.minuteselect').val(), 10); + var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0; + + if (!this.timePicker24Hour) { + var ampm = cal.find('.ampmselect').val(); + if (ampm === 'PM' && hour < 12) + hour += 12; + if (ampm === 'AM' && hour === 12) + hour = 0; + } + + if (isLeft) { + var start = this.startDate.clone(); + start.hour(hour); + start.minute(minute); + start.second(second); + this.setStartDate(start); + if (this.singleDatePicker) { + this.endDate = this.startDate.clone(); + } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) { + this.setEndDate(start.clone()); + } + } else if (this.endDate) { + var end = this.endDate.clone(); + end.hour(hour); + end.minute(minute); + end.second(second); + this.setEndDate(end); + } + + //update the calendars so all clickable dates reflect the new time component + this.updateCalendars(); + + //update the form inputs above the calendars with the new time + this.updateFormInputs(); + + //re-render the time pickers because changing one selection can affect what's enabled in another + this.renderTimePicker('left'); + this.renderTimePicker('right'); + + }, + + formInputsChanged: function(e) { + var isRight = $(e.target).closest('.calendar').hasClass('right'); + var start = moment(this.container.find('input[name="daterangepicker_start"]').val(), this.locale.format); + var end = moment(this.container.find('input[name="daterangepicker_end"]').val(), this.locale.format); + + if (start.isValid() && end.isValid()) { + + if (isRight && end.isBefore(start)) + start = end.clone(); + + this.setStartDate(start); + this.setEndDate(end); + + if (isRight) { + this.container.find('input[name="daterangepicker_start"]').val(this.startDate.format(this.locale.format)); + } else { + this.container.find('input[name="daterangepicker_end"]').val(this.endDate.format(this.locale.format)); + } + + } + + this.updateView(); + }, + + formInputsFocused: function(e) { + + // Highlight the focused input + this.container.find('input[name="daterangepicker_start"], input[name="daterangepicker_end"]').removeClass('active'); + $(e.target).addClass('active'); + + // Set the state such that if the user goes back to using a mouse, + // the calendars are aware we're selecting the end of the range, not + // the start. This allows someone to edit the end of a date range without + // re-selecting the beginning, by clicking on the end date input then + // using the calendar. + var isRight = $(e.target).closest('.calendar').hasClass('right'); + if (isRight) { + this.endDate = null; + this.setStartDate(this.startDate.clone()); + this.updateView(); + } + + }, + + formInputsBlurred: function(e) { + + // this function has one purpose right now: if you tab from the first + // text input to the second in the UI, the endDate is nulled so that + // you can click another, but if you tab out without clicking anything + // or changing the input value, the old endDate should be retained + + if (!this.endDate) { + var val = this.container.find('input[name="daterangepicker_end"]').val(); + var end = moment(val, this.locale.format); + if (end.isValid()) { + this.setEndDate(end); + this.updateView(); + } + } + + }, + + formInputsKeydown: function(e) { + // This function ensures that if the 'enter' key was pressed in the input, then the calendars + // are updated with the startDate and endDate. + // This behaviour is automatic in Chrome/Firefox/Edge but not in IE 11 hence why this exists. + // Other browsers and versions of IE are untested and the behaviour is unknown. + if (e.keyCode === 13) { + // Prevent the calendar from being updated twice on Chrome/Firefox/Edge + e.preventDefault(); + this.formInputsChanged(e); + } + }, + + + elementChanged: function() { + if (!this.element.is('input')) return; + if (!this.element.val().length) return; + + var dateString = this.element.val().split(this.locale.separator), + start = null, + end = null; + + if (dateString.length === 2) { + start = moment(dateString[0], this.locale.format); + end = moment(dateString[1], this.locale.format); + } + + if (this.singleDatePicker || start === null || end === null) { + start = moment(this.element.val(), this.locale.format); + end = start; + } + + if (!start.isValid() || !end.isValid()) return; + + this.setStartDate(start); + this.setEndDate(end); + this.updateView(); + }, + + keydown: function(e) { + //hide on tab or enter + if ((e.keyCode === 9) || (e.keyCode === 13)) { + this.hide(); + } + + //hide on esc and prevent propagation + if (e.keyCode === 27) { + e.preventDefault(); + e.stopPropagation(); + + this.hide(); + } + }, + + updateElement: function() { + if (this.element.is('input') && !this.singleDatePicker && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); + this.element.trigger('change'); + } else if (this.element.is('input') && this.autoUpdateInput) { + this.element.val(this.startDate.format(this.locale.format)); + this.element.trigger('change'); + } + }, + + remove: function() { + this.container.remove(); + this.element.off('.daterangepicker'); + this.element.removeData(); + } + + }; + + $.fn.daterangepicker = function(options, callback) { + var implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options); + this.each(function() { + var el = $(this); + if (el.data('daterangepicker')) + el.data('daterangepicker').remove(); + el.data('daterangepicker', new DateRangePicker(el, implementOptions, callback)); + }); + return this; + }; + + return DateRangePicker; + +})); diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css new file mode 100644 index 0000000..5b96335 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css @@ -0,0 +1,6 @@ +/*! + * Bootstrap v3.4.1 (https://getbootstrap.com/) + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}@font-face{font-family:"Glyphicons Halflings";src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format("embedded-opentype"),url(../fonts/glyphicons-halflings-regular.woff2) format("woff2"),url(../fonts/glyphicons-halflings-regular.woff) format("woff"),url(../fonts/glyphicons-halflings-regular.ttf) format("truetype"),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format("svg")}.glyphicon{position:relative;top:1px;display:inline-block;font-family:"Glyphicons Halflings";font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-eur:before,.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:"\2014 \00A0"}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:""}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:"\00A0 \2014"}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.row-no-gutters{margin-right:0;margin-left:0}.row-no-gutters [class*=col-]{padding-right:0;padding-left:0}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s,-webkit-box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{background-color:transparent;border:0}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.form-control-static{min-height:34px;padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;filter:alpha(opacity=65);opacity:.65;-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;background-image:none;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;background-image:none;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;background-image:none;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;background-image:none;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;background-image:none;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;background-image:none;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-right:15px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-right:-15px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#337ab7;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{padding-right:15px;padding-left:15px;border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-right:60px;padding-left:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0%;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out,-o-transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:12px;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;line-height:1.42857143;line-break:auto;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;font-size:14px;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover>.arrow{border-width:11px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out,-o-transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:rgba(0,0,0,0);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:focus,.carousel-control:hover{color:#fff;text-decoration:none;outline:0;filter:alpha(opacity=90);opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.carousel-control .icon-prev:before{content:"\2039"}.carousel-control .icon-next:before{content:"\203a"}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000\9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.modal-header:after,.modal-header:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.modal-header:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css.map b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css.map new file mode 100644 index 0000000..0ae3de5 --- /dev/null +++ b/zhi-extend/zhi-xxl-job-admin/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["bootstrap.css","less/normalize.less","dist/css/bootstrap.css","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA;;;;AAKA,4ECKA,KACE,YAAA,WACA,qBAAA,KACA,yBAAA,KAOF,KACE,OAAA,EAaF,QCnBA,MACA,QACA,WACA,OACA,OACA,OACA,OACA,KACA,KACA,IACA,QACA,QDqBE,QAAA,MAQF,MCzBA,OACA,SACA,MD2BE,QAAA,aACA,eAAA,SAQF,sBACE,QAAA,KACA,OAAA,EAQF,SCrCA,SDuCE,QAAA,KAUF,EACE,iBAAA,YAQF,SCnDA,QDqDE,QAAA,EAWF,YACE,cAAA,KACA,gBAAA,UACA,wBAAA,UAAA,OAAA,qBAAA,UAAA,OAAA,gBAAA,UAAA,OAOF,EC/DA,ODiEE,YAAA,IAOF,IACE,WAAA,OAQF,GACE,UAAA,IACA,OAAA,MAAA,EAOF,KACE,WAAA,KACA,MAAA,KAOF,MACE,UAAA,IAOF,ICzFA,ID2FE,UAAA,IACA,YAAA,EACA,SAAA,SACA,eAAA,SAGF,IACE,IAAA,MAGF,IACE,OAAA,OAUF,IACE,OAAA,EAOF,eACE,SAAA,OAUF,OACE,OAAA,IAAA,KAOF,GACE,mBAAA,YAAA,gBAAA,YAAA,WAAA,YACA,OAAA,EAOF,IACE,SAAA,KAOF,KC7HA,IACA,IACA,KD+HE,YAAA,SAAA,CAAA,UACA,UAAA,IAkBF,OC7IA,MACA,SACA,OACA,SD+IE,MAAA,QACA,KAAA,QACA,OAAA,EAOF,OACE,SAAA,QAUF,OC1JA,OD4JE,eAAA,KAWF,OCnKA,wBACA,kBACA,mBDqKE,mBAAA,OACA,OAAA,QAOF,iBCxKA,qBD0KE,OAAA,QAOF,yBC7KA,wBD+KE,OAAA,EACA,QAAA,EAQF,MACE,YAAA,OAWF,qBC5LA,kBD8LE,mBAAA,WAAA,gBAAA,WAAA,WAAA,WACA,QAAA,EASF,8CCjMA,8CDmME,OAAA,KAQF,mBACE,mBAAA,UACA,mBAAA,YAAA,gBAAA,YAAA,WAAA,YASF,iDC5MA,8CD8ME,mBAAA,KAOF,SACE,OAAA,IAAA,MAAA,OACA,OAAA,EAAA,IACA,QAAA,MAAA,OAAA,MAQF,OACE,OAAA,EACA,QAAA,EAOF,SACE,SAAA,KAQF,SACE,YAAA,IAUF,MACE,gBAAA,SACA,eAAA,EAGF,GC3OA,GD6OE,QAAA,EDlPF,qFGhLA,aACE,ED2LA,OADA,QCvLE,MAAA,eACA,YAAA,eACA,WAAA,cACA,mBAAA,eAAA,WAAA,eAGF,ED0LA,UCxLE,gBAAA,UAGF,cACE,QAAA,KAAA,WAAA,IAGF,kBACE,QAAA,KAAA,YAAA,IAKF,mBDqLA,6BCnLE,QAAA,GDuLF,WCpLA,IAEE,OAAA,IAAA,MAAA,KACA,kBAAA,MAGF,MACE,QAAA,mBDqLF,IClLA,GAEE,kBAAA,MAGF,IACE,UAAA,eDmLF,GACA,GCjLA,EAGE,QAAA,EACA,OAAA,EAGF,GD+KA,GC7KE,iBAAA,MAMF,QACE,QAAA,KAEF,YD2KA,oBCxKI,iBAAA,eAGJ,OACE,OAAA,IAAA,MAAA,KAGF,OACE,gBAAA,mBADF,UD2KA,UCtKI,iBAAA,eD0KJ,mBCvKA,mBAGI,OAAA,IAAA,MAAA,gBCrFN,WACE,YAAA,uBACA,IAAA,+CACA,IAAA,sDAAA,2BAAA,CAAA,iDAAA,eAAA,CAAA,gDAAA,cAAA,CAAA,+CAAA,kBAAA,CAAA,2EAAA,cAQF,WACE,SAAA,SACA,IAAA,IACA,QAAA,aACA,YAAA,uBACA,WAAA,OACA,YAAA,IACA,YAAA,EACA,uBAAA,YACA,wBAAA,UAIkC,2BAAW,QAAA,QACX,uBAAW,QAAA,QF2P/C,sBEzPoC,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,qBAAW,QAAA,QACX,0BAAW,QAAA,QACX,qBAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,2BAAW,QAAA,QACX,sBAAW,QAAA,QACX,yBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,+BAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,8BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,yBAAW,QAAA,QACX,8BAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,gCAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,iCAAW,QAAA,QACX,0BAAW,QAAA,QACX,6BAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,gCAAW,QAAA,QACX,gCAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,0BAAW,QAAA,QACX,+BAAW,QAAA,QACX,+BAAW,QAAA,QACX,wBAAW,QAAA,QACX,+BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,0BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,gCAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,6BAAW,QAAA,QACX,8BAAW,QAAA,QACX,2BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,mCAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,+BAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,yBAAW,QAAA,QACX,0BAAW,QAAA,QACX,yBAAW,QAAA,QACX,6BAAW,QAAA,QACX,+BAAW,QAAA,QACX,0BAAW,QAAA,QACX,gCAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,kCAAW,QAAA,QACX,oCAAW,QAAA,QACX,sBAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,0BAAW,QAAA,QACX,4BAAW,QAAA,QACX,qCAAW,QAAA,QACX,oCAAW,QAAA,QACX,kCAAW,QAAA,QACX,oCAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,8BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,uBAAW,QAAA,QACX,mCAAW,QAAA,QACX,uCAAW,QAAA,QACX,gCAAW,QAAA,QACX,oCAAW,QAAA,QACX,qCAAW,QAAA,QACX,yCAAW,QAAA,QACX,4BAAW,QAAA,QACX,yBAAW,QAAA,QACX,gCAAW,QAAA,QACX,8BAAW,QAAA,QACX,yBAAW,QAAA,QACX,wBAAW,QAAA,QACX,0BAAW,QAAA,QACX,6BAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,yBAAW,QAAA,QACX,yBAAW,QAAA,QACX,uBAAW,QAAA,QACX,8BAAW,QAAA,QACX,+BAAW,QAAA,QACX,gCAAW,QAAA,QACX,8BAAW,QAAA,QACX,8BAAW,QAAA,QACX,8BAAW,QAAA,QACX,2BAAW,QAAA,QACX,0BAAW,QAAA,QACX,yBAAW,QAAA,QACX,6BAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,2BAAW,QAAA,QACX,2BAAW,QAAA,QACX,4BAAW,QAAA,QACX,+BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,iCAAW,QAAA,QACX,oCAAW,QAAA,QACX,iCAAW,QAAA,QACX,+BAAW,QAAA,QACX,+BAAW,QAAA,QACX,iCAAW,QAAA,QACX,qBAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,2BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QASX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,uBAAW,QAAA,QACX,wBAAW,QAAA,QACX,uBAAW,QAAA,QACX,yBAAW,QAAA,QACX,yBAAW,QAAA,QACX,+BAAW,QAAA,QACX,uBAAW,QAAA,QACX,6BAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,uBAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,2BAAW,QAAA,QACX,0BAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,4BAAW,QAAA,QACX,mCAAW,QAAA,QACX,4BAAW,QAAA,QACX,oCAAW,QAAA,QACX,kCAAW,QAAA,QACX,iCAAW,QAAA,QACX,+BAAW,QAAA,QACX,sBAAW,QAAA,QACX,wBAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,kCAAW,QAAA,QACX,mCAAW,QAAA,QACX,sCAAW,QAAA,QACX,0CAAW,QAAA,QACX,oCAAW,QAAA,QACX,wCAAW,QAAA,QACX,qCAAW,QAAA,QACX,iCAAW,QAAA,QACX,gCAAW,QAAA,QACX,kCAAW,QAAA,QACX,+BAAW,QAAA,QACX,0BAAW,QAAA,QACX,8BAAW,QAAA,QACX,4BAAW,QAAA,QACX,4BAAW,QAAA,QACX,6BAAW,QAAA,QACX,4BAAW,QAAA,QACX,0BAAW,QAAA,QCxS/C,ECkEE,mBAAA,WACG,gBAAA,WACK,WAAA,WJo+BV,OGriCA,QC+DE,mBAAA,WACG,gBAAA,WACK,WAAA,WDzDV,KACE,UAAA,KACA,4BAAA,cAGF,KACE,YAAA,gBAAA,CAAA,SAAA,CAAA,KAAA,CAAA,WACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,iBAAA,KHoiCF,OGhiCA,MHiiCA,OACA,SG9hCE,YAAA,QACA,UAAA,QACA,YAAA,QAMF,EACE,MAAA,QACA,gBAAA,KH8hCF,QG5hCE,QAEE,MAAA,QACA,gBAAA,UAGF,QEnDA,QAAA,IAAA,KAAA,yBACA,eAAA,KF6DF,OACE,OAAA,EAMF,IACE,eAAA,OHqhCF,4BADA,0BGhhCA,gBH+gCA,iBADA,eMxlCE,QAAA,MACA,UAAA,KACA,OAAA,KH6EF,aACE,cAAA,IAMF,eACE,QAAA,IACA,YAAA,WACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,IC+FA,mBAAA,IAAA,IAAA,YACK,cAAA,IAAA,IAAA,YACG,WAAA,IAAA,IAAA,YE5LR,QAAA,aACA,UAAA,KACA,OAAA,KHiGF,YACE,cAAA,IAMF,GACE,WAAA,KACA,cAAA,KACA,OAAA,EACA,WAAA,IAAA,MAAA,KAQF,SACE,SAAA,SACA,MAAA,IACA,OAAA,IACA,QAAA,EACA,OAAA,KACA,SAAA,OACA,KAAA,cACA,OAAA,EAQA,0BH8/BF,yBG5/BI,SAAA,OACA,MAAA,KACA,OAAA,KACA,OAAA,EACA,SAAA,QACA,KAAA,KAWJ,cACE,OAAA,QH4/BF,IACA,IACA,IACA,IACA,IACA,IOtpCA,GP4oCA,GACA,GACA,GACA,GACA,GO9oCE,YAAA,QACA,YAAA,IACA,YAAA,IACA,MAAA,QPyqCF,WAZA,UAaA,WAZA,UAaA,WAZA,UAaA,WAZA,UAaA,WAZA,UAaA,WAZA,UACA,UOxqCA,SPyqCA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SAaA,UAZA,SOxpCI,YAAA,IACA,YAAA,EACA,MAAA,KP8qCJ,IAEA,IAEA,IO9qCA,GP2qCA,GAEA,GO1qCE,WAAA,KACA,cAAA,KPqrCF,WANA,UAQA,WANA,UAQA,WANA,UACA,UOxrCA,SP0rCA,UANA,SAQA,UANA,SO9qCI,UAAA,IPyrCJ,IAEA,IAEA,IO1rCA,GPurCA,GAEA,GOtrCE,WAAA,KACA,cAAA,KPisCF,WANA,UAQA,WANA,UAQA,WANA,UACA,UOpsCA,SPssCA,UANA,SAQA,UANA,SO1rCI,UAAA,IPqsCJ,IOjsCA,GAAU,UAAA,KPqsCV,IOpsCA,GAAU,UAAA,KPwsCV,IOvsCA,GAAU,UAAA,KP2sCV,IO1sCA,GAAU,UAAA,KP8sCV,IO7sCA,GAAU,UAAA,KPitCV,IOhtCA,GAAU,UAAA,KAMV,EACE,OAAA,EAAA,EAAA,KAGF,MACE,cAAA,KACA,UAAA,KACA,YAAA,IACA,YAAA,IAEA,yBAAA,MACE,UAAA,MPitCJ,OOxsCA,MAEE,UAAA,IP0sCF,MOvsCA,KAEE,QAAA,KACA,iBAAA,QAIF,WAAuB,WAAA,KACvB,YAAuB,WAAA,MACvB,aAAuB,WAAA,OACvB,cAAuB,WAAA,QACvB,aAAuB,YAAA,OAGvB,gBAAuB,eAAA,UACvB,gBAAuB,eAAA,UACvB,iBAAuB,eAAA,WAGvB,YACE,MAAA,KAEF,cCvGE,MAAA,QR2zCF,qBQ1zCE,qBAEE,MAAA,QDuGJ,cC1GE,MAAA,QRk0CF,qBQj0CE,qBAEE,MAAA,QD0GJ,WC7GE,MAAA,QRy0CF,kBQx0CE,kBAEE,MAAA,QD6GJ,cChHE,MAAA,QRg1CF,qBQ/0CE,qBAEE,MAAA,QDgHJ,aCnHE,MAAA,QRu1CF,oBQt1CE,oBAEE,MAAA,QDuHJ,YAGE,MAAA,KE7HA,iBAAA,QT+1CF,mBS91CE,mBAEE,iBAAA,QF6HJ,YEhIE,iBAAA,QTs2CF,mBSr2CE,mBAEE,iBAAA,QFgIJ,SEnIE,iBAAA,QT62CF,gBS52CE,gBAEE,iBAAA,QFmIJ,YEtIE,iBAAA,QTo3CF,mBSn3CE,mBAEE,iBAAA,QFsIJ,WEzIE,iBAAA,QT23CF,kBS13CE,kBAEE,iBAAA,QF8IJ,aACE,eAAA,IACA,OAAA,KAAA,EAAA,KACA,cAAA,IAAA,MAAA,KPgvCF,GOxuCA,GAEE,WAAA,EACA,cAAA,KP4uCF,MAFA,MACA,MO9uCA,MAMI,cAAA,EAOJ,eACE,aAAA,EACA,WAAA,KAIF,aALE,aAAA,EACA,WAAA,KAMA,YAAA,KAFF,gBAKI,QAAA,aACA,cAAA,IACA,aAAA,IAKJ,GACE,WAAA,EACA,cAAA,KPouCF,GOluCA,GAEE,YAAA,WAEF,GACE,YAAA,IAEF,GACE,YAAA,EAaA,yBAAA,kBAEI,MAAA,KACA,MAAA,MACA,MAAA,KACA,WAAA,MGxNJ,SAAA,OACA,cAAA,SACA,YAAA,OHiNA,kBASI,YAAA,OP4tCN,0BOjtCA,YAEE,OAAA,KAGF,YACE,UAAA,IA9IqB,eAAA,UAmJvB,WACE,QAAA,KAAA,KACA,OAAA,EAAA,EAAA,KACA,UAAA,OACA,YAAA,IAAA,MAAA,KPitCF,yBO5sCI,wBP2sCJ,yBO1sCM,cAAA,EPgtCN,kBO1tCA,kBPytCA,iBOtsCI,QAAA,MACA,UAAA,IACA,YAAA,WACA,MAAA,KP4sCJ,yBO1sCI,yBPysCJ,wBOxsCM,QAAA,cAQN,oBPqsCA,sBOnsCE,cAAA,KACA,aAAA,EACA,WAAA,MACA,aAAA,IAAA,MAAA,KACA,YAAA,EP0sCF,kCOpsCI,kCPksCJ,iCAGA,oCAJA,oCAEA,mCOnsCe,QAAA,GP4sCf,iCO3sCI,iCPysCJ,gCAGA,mCAJA,mCAEA,kCOzsCM,QAAA,cAMN,QACE,cAAA,KACA,WAAA,OACA,YAAA,WIxSF,KXm/CA,IACA,IACA,KWj/CE,YAAA,KAAA,CAAA,MAAA,CAAA,QAAA,CAAA,aAAA,CAAA,UAIF,KACE,QAAA,IAAA,IACA,UAAA,IACA,MAAA,QACA,iBAAA,QACA,cAAA,IAIF,IACE,QAAA,IAAA,IACA,UAAA,IACA,MAAA,KACA,iBAAA,KACA,cAAA,IACA,mBAAA,MAAA,EAAA,KAAA,EAAA,gBAAA,WAAA,MAAA,EAAA,KAAA,EAAA,gBANF,QASI,QAAA,EACA,UAAA,KACA,YAAA,IACA,mBAAA,KAAA,WAAA,KAKJ,IACE,QAAA,MACA,QAAA,MACA,OAAA,EAAA,EAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,WAAA,UACA,UAAA,WACA,iBAAA,QACA,OAAA,IAAA,MAAA,KACA,cAAA,IAXF,SAeI,QAAA,EACA,UAAA,QACA,MAAA,QACA,YAAA,SACA,iBAAA,YACA,cAAA,EAKJ,gBACE,WAAA,MACA,WAAA,OC1DF,WCHE,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KDGA,yBAAA,WACE,MAAA,OAEF,yBAAA,WACE,MAAA,OAEF,0BAAA,WACE,MAAA,QAUJ,iBCvBE,cAAA,KACA,aAAA,KACA,aAAA,KACA,YAAA,KD6BF,KCvBE,aAAA,MACA,YAAA,MD0BF,gBACE,aAAA,EACA,YAAA,EAFF,8BAKI,cAAA,EACA,aAAA,EZwiDJ,UAoCA,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAjCA,UAoCA,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAjCA,UAoCA,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UatnDC,UbynDD,WAIA,WAIA,WAxCA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UAIA,UcpmDM,SAAA,SAEA,WAAA,IAEA,cAAA,KACA,aAAA,KDtBL,UbmpDD,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,Uc3mDM,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,EFCJ,yBCzEC,Ub2zDC,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UcnxDI,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,GFUJ,yBClFC,Ubo+DC,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,Uc57DI,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,GFmBJ,0BC3FC,Ub6oEC,WACA,WACA,WAVA,UACA,UACA,UACA,UACA,UACA,UACA,UACA,UcrmEI,MAAA,KDvCL,WC+CG,MAAA,KD/CH,WC+CG,MAAA,aD/CH,WC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,ID/CH,UC+CG,MAAA,aD/CH,UC+CG,MAAA,YD/CH,gBC8DG,MAAA,KD9DH,gBC8DG,MAAA,aD9DH,gBC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,ID9DH,eC8DG,MAAA,aD9DH,eC8DG,MAAA,YD9DH,eCmEG,MAAA,KDnEH,gBCoDG,KAAA,KDpDH,gBCoDG,KAAA,aDpDH,gBCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,IDpDH,eCoDG,KAAA,aDpDH,eCoDG,KAAA,YDpDH,eCyDG,KAAA,KDzDH,kBCwEG,YAAA,KDxEH,kBCwEG,YAAA,aDxEH,kBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,IDxEH,iBCwEG,YAAA,aDxEH,iBCwEG,YAAA,YDxEH,iBCwEG,YAAA,GCjEJ,MACE,iBAAA,YADF,uBAQI,SAAA,OACA,QAAA,aACA,MAAA,KAKA,sBf+xEJ,sBe9xEM,SAAA,OACA,QAAA,WACA,MAAA,KAKN,QACE,YAAA,IACA,eAAA,IACA,MAAA,KACA,WAAA,KAGF,GACE,WAAA,KAMF,OACE,MAAA,KACA,UAAA,KACA,cAAA,Kf6xEF,mBAHA,mBAIA,mBAHA,mBACA,mBe/xEA,mBAWQ,QAAA,IACA,YAAA,WACA,eAAA,IACA,WAAA,IAAA,MAAA,KAdR,mBAoBI,eAAA,OACA,cAAA,IAAA,MAAA,KfyxEJ,uCe9yEA,uCf+yEA,wCAHA,wCAIA,2CAHA,2Ce/wEQ,WAAA,EA9BR,mBAoCI,WAAA,IAAA,MAAA,KApCJ,cAyCI,iBAAA,KfoxEJ,6BAHA,6BAIA,6BAHA,6BACA,6Be5wEA,6BAOQ,QAAA,IAWR,gBACE,OAAA,IAAA,MAAA,KfqwEF,4BAHA,4BAIA,4BAHA,4BACA,4BerwEA,4BAQQ,OAAA,IAAA,MAAA,KfmwER,4Be3wEA,4BAeM,oBAAA,IAUN,yCAEI,iBAAA,QASJ,4BAEI,iBAAA,QfqvEJ,0BAGA,0BATA,0BAGA,0BAIA,0BAGA,0BATA,0BAGA,0BACA,0BAGA,0BgBt4EE,0BhBg4EF,0BgBz3EM,iBAAA,QhBs4EN,sCAEA,sCADA,oCgBj4EE,sChB+3EF,sCgBz3EM,iBAAA,QhBs4EN,2BAGA,2BATA,2BAGA,2BAIA,2BAGA,2BATA,2BAGA,2BACA,2BAGA,2BgB35EE,2BhBq5EF,2BgB94EM,iBAAA,QhB25EN,uCAEA,uCADA,qCgBt5EE,uChBo5EF,uCgB94EM,iBAAA,QhB25EN,wBAGA,wBATA,wBAGA,wBAIA,wBAGA,wBATA,wBAGA,wBACA,wBAGA,wBgBh7EE,wBhB06EF,wBgBn6EM,iBAAA,QhBg7EN,oCAEA,oCADA,kCgB36EE,oChBy6EF,oCgBn6EM,iBAAA,QhBg7EN,2BAGA,2BATA,2BAGA,2BAIA,2BAGA,2BATA,2BAGA,2BACA,2BAGA,2BgBr8EE,2BhB+7EF,2BgBx7EM,iBAAA,QhBq8EN,uCAEA,uCADA,qCgBh8EE,uChB87EF,uCgBx7EM,iBAAA,QhBq8EN,0BAGA,0BATA,0BAGA,0BAIA,0BAGA,0BATA,0BAGA,0BACA,0BAGA,0BgB19EE,0BhBo9EF,0BgB78EM,iBAAA,QhB09EN,sCAEA,sCADA,oCgBr9EE,sChBm9EF,sCgB78EM,iBAAA,QDoJN,kBACE,WAAA,KACA,WAAA,KAEA,oCAAA,kBACE,MAAA,KACA,cAAA,KACA,WAAA,OACA,mBAAA,yBACA,OAAA,IAAA,MAAA,KALF,yBASI,cAAA,Efq0EJ,qCAHA,qCAIA,qCAHA,qCACA,qCe70EA,qCAkBU,YAAA,OAlBV,kCA0BI,OAAA,Ef+zEJ,0DAHA,0DAIA,0DAHA,0DACA,0Dex1EA,0DAmCU,YAAA,Ef8zEV,yDAHA,yDAIA,yDAHA,yDACA,yDeh2EA,yDAuCU,aAAA,Efg0EV,yDev2EA,yDfw2EA,yDAFA,yDelzEU,cAAA,GEzNZ,SAIE,UAAA,EACA,QAAA,EACA,OAAA,EACA,OAAA,EAGF,OACE,QAAA,MACA,MAAA,KACA,QAAA,EACA,cAAA,KACA,UAAA,KACA,YAAA,QACA,MAAA,KACA,OAAA,EACA,cAAA,IAAA,MAAA,QAGF,MACE,QAAA,aACA,UAAA,KACA,cAAA,IACA,YAAA,IAUF,mBb6BE,mBAAA,WACG,gBAAA,WACK,WAAA,WarBR,mBAAA,KACA,gBAAA,KAAA,WAAA,KjBkgFF,qBiB9/EA,kBAEE,OAAA,IAAA,EAAA,EACA,WAAA,MACA,YAAA,OjBogFF,wCADA,qCADA,8BAFA,+BACA,2BiB3/EE,4BAGE,OAAA,YAIJ,iBACE,QAAA,MAIF,kBACE,QAAA,MACA,MAAA,KAIF,iBjBu/EA,aiBr/EE,OAAA,KjB0/EF,2BiBt/EA,uBjBq/EA,wBK/kFE,QAAA,IAAA,KAAA,yBACA,eAAA,KYgGF,OACE,QAAA,MACA,YAAA,IACA,UAAA,KACA,YAAA,WACA,MAAA,KA0BF,cACE,QAAA,MACA,MAAA,KACA,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,iBAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,Ib3EA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBAyHR,mBAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KACK,cAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KACG,mBAAA,aAAA,YAAA,IAAA,CAAA,mBAAA,YAAA,KAAA,WAAA,aAAA,YAAA,IAAA,CAAA,mBAAA,YAAA,KAAA,WAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,KAAA,WAAA,aAAA,YAAA,IAAA,CAAA,WAAA,YAAA,IAAA,CAAA,mBAAA,YAAA,Kc1IR,oBACE,aAAA,QACA,QAAA,EdYF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,qBAiCR,gCACE,MAAA,KACA,QAAA,EAEF,oCAA0B,MAAA,KAC1B,yCAAgC,MAAA,Ka+ChC,0BACE,iBAAA,YACA,OAAA,EAQF,wBjBq+EF,wBACA,iCiBn+EI,iBAAA,KACA,QAAA,EAGF,wBjBo+EF,iCiBl+EI,OAAA,YAIF,sBACE,OAAA,KAcJ,qDAKI,8BjBm9EF,wCACA,+BAFA,8BiBj9EI,YAAA,KjB09EJ,iCAEA,2CACA,kCAFA,iCiBx9EE,0BjBq9EF,oCACA,2BAFA,0BiBl9EI,YAAA,KjB+9EJ,iCAEA,2CACA,kCAFA,iCiB79EE,0BjB09EF,oCACA,2BAFA,0BiBv9EI,YAAA,MAWN,YACE,cAAA,KjBy9EF,UiBj9EA,OAEE,SAAA,SACA,QAAA,MACA,WAAA,KACA,cAAA,KjBm9EF,yBiBh9EE,sBjBk9EF,mCADA,gCiB98EM,OAAA,YjBm9EN,gBiB99EA,aAgBI,WAAA,KACA,aAAA,KACA,cAAA,EACA,YAAA,IACA,OAAA,QjBm9EJ,+BACA,sCiBj9EA,yBjB+8EA,gCiB38EE,SAAA,SACA,WAAA,MACA,YAAA,MjBi9EF,oBiB98EA,cAEE,WAAA,KjBg9EF,iBiB58EA,cAEE,SAAA,SACA,QAAA,aACA,aAAA,KACA,cAAA,EACA,YAAA,IACA,eAAA,OACA,OAAA,QjB88EF,0BiB38EE,uBjB68EF,oCADA,iCiB18EI,OAAA,YjB+8EJ,kCiB58EA,4BAEE,WAAA,EACA,YAAA,KASF,qBACE,WAAA,KAEA,YAAA,IACA,eAAA,IAEA,cAAA,EAEA,8BjBm8EF,8BiBj8EI,cAAA,EACA,aAAA,EAaJ,UC3PE,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IAEA,gBACE,OAAA,KACA,YAAA,KlBsrFJ,0BkBnrFE,kBAEE,OAAA,KDiPJ,6BAEI,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IANJ,mCASI,OAAA,KACA,YAAA,KjBq8EJ,6CiB/8EA,qCAcI,OAAA,KAdJ,oCAiBI,OAAA,KACA,WAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IAIJ,UCvRE,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IAEA,gBACE,OAAA,KACA,YAAA,KlB2tFJ,0BkBxtFE,kBAEE,OAAA,KD6QJ,6BAEI,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IANJ,mCASI,OAAA,KACA,YAAA,KjB88EJ,6CiBx9EA,qCAcI,OAAA,KAdJ,oCAiBI,OAAA,KACA,WAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UASJ,cAEE,SAAA,SAFF,4BAMI,cAAA,OAIJ,uBACE,SAAA,SACA,IAAA,EACA,MAAA,EACA,QAAA,EACA,QAAA,MACA,MAAA,KACA,OAAA,KACA,YAAA,KACA,WAAA,OACA,eAAA,KjBo8EF,oDADA,uCiBj8EA,iCAGE,MAAA,KACA,OAAA,KACA,YAAA,KjBo8EF,oDADA,uCiBj8EA,iCAGE,MAAA,KACA,OAAA,KACA,YAAA,KjBq8EF,uBAEA,8BAJA,4BiB/7EA,yBjBg8EA,oBAEA,2BAGA,4BAEA,mCAHA,yBAEA,gCkBx1FI,MAAA,QDkZJ,2BC9YI,aAAA,QdiDF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBchDN,iCACE,aAAA,Qd8CJ,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,Qa4VV,gCCpYI,MAAA,QACA,iBAAA,QACA,aAAA,QDkYJ,oCC9XI,MAAA,QlB61FJ,uBAEA,8BAJA,4BiB19EA,yBjB29EA,oBAEA,2BAGA,4BAEA,mCAHA,yBAEA,gCkBt3FI,MAAA,QDqZJ,2BCjZI,aAAA,QdiDF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBchDN,iCACE,aAAA,Qd8CJ,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,Qa+VV,gCCvYI,MAAA,QACA,iBAAA,QACA,aAAA,QDqYJ,oCCjYI,MAAA,QlB23FJ,qBAEA,4BAJA,0BiBr/EA,uBjBs/EA,kBAEA,yBAGA,0BAEA,iCAHA,uBAEA,8BkBp5FI,MAAA,QDwZJ,yBCpZI,aAAA,QdiDF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBchDN,+BACE,aAAA,Qd8CJ,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,CAAA,EAAA,EAAA,IAAA,QakWV,8BC1YI,MAAA,QACA,iBAAA,QACA,aAAA,QDwYJ,kCCpYI,MAAA,QD2YF,2CACE,IAAA,KAEF,mDACE,IAAA,EAUJ,YACE,QAAA,MACA,WAAA,IACA,cAAA,KACA,MAAA,QAkBA,yBAAA,yBAGI,QAAA,aACA,cAAA,EACA,eAAA,OALJ,2BAUI,QAAA,aACA,MAAA,KACA,eAAA,OAZJ,kCAiBI,QAAA,aAjBJ,0BAqBI,QAAA,aACA,eAAA,OjBi/EJ,wCiBvgFA,6CjBsgFA,2CiB3+EM,MAAA,KA3BN,wCAiCI,MAAA,KAjCJ,4BAqCI,cAAA,EACA,eAAA,OjB4+EJ,uBiBlhFA,oBA6CI,QAAA,aACA,WAAA,EACA,cAAA,EACA,eAAA,OjBy+EJ,6BiBzhFA,0BAmDM,aAAA,EjB0+EN,4CiB7hFA,sCAwDI,SAAA,SACA,YAAA,EAzDJ,kDA8DI,IAAA,GjBw+EN,2BAEA,kCiB/9EA,wBjB89EA,+BiBr9EI,YAAA,IACA,WAAA,EACA,cAAA,EjB09EJ,2BiBr+EA,wBAiBI,WAAA,KAjBJ,6BJ9gBE,aAAA,MACA,YAAA,MIwiBA,yBAAA,gCAEI,YAAA,IACA,cAAA,EACA,WAAA,OA/BN,sDAwCI,MAAA,KAQA,yBAAA,+CAEI,YAAA,KACA,UAAA,MAKJ,yBAAA,+CAEI,YAAA,IACA,UAAA,ME9kBR,KACE,QAAA,aACA,cAAA,EACA,YAAA,IACA,WAAA,OACA,YAAA,OACA,eAAA,OACA,iBAAA,aAAA,aAAA,aACA,OAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,YCoCA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,cAAA,IhBqKA,oBAAA,KACG,iBAAA,KACC,gBAAA,KACI,YAAA,KJs1FV,kBAHA,kBACA,WACA,kBAHA,kBmB1hGI,WdrBF,QAAA,IAAA,KAAA,yBACA,eAAA,KLwjGF,WADA,WmB7hGE,WAGE,MAAA,KACA,gBAAA,KnB+hGJ,YmB5hGE,YAEE,iBAAA,KACA,QAAA,Ef2BF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBexBR,cnB4hGF,eACA,wBmB1hGI,OAAA,YE9CF,OAAA,kBACA,QAAA,IjBiEA,mBAAA,KACQ,WAAA,KefN,enB4hGJ,yBmB1hGM,eAAA,KASN,aC7DE,MAAA,KACA,iBAAA,KACA,aAAA,KpBqlGF,mBoBnlGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpBqlGJ,oBoBnlGE,oBpBolGF,mCoBjlGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpB2lGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoBrlGI,0BpB0lGJ,yCAHA,yCAHA,yCoBjlGM,MAAA,KACA,iBAAA,QACA,aAAA,QpBgmGN,4BAHA,4BoBvlGI,4BpB2lGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoBnlGM,iBAAA,KACA,aAAA,KDuBN,oBClBI,MAAA,KACA,iBAAA,KDoBJ,aChEE,MAAA,KACA,iBAAA,QACA,aAAA,QpB0oGF,mBoBxoGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpB0oGJ,oBoBxoGE,oBpByoGF,mCoBtoGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpBgpGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoB1oGI,0BpB+oGJ,yCAHA,yCAHA,yCoBtoGM,MAAA,KACA,iBAAA,QACA,aAAA,QpBqpGN,4BAHA,4BoB5oGI,4BpBgpGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoBxoGM,iBAAA,QACA,aAAA,QD0BN,oBCrBI,MAAA,QACA,iBAAA,KDwBJ,aCpEE,MAAA,KACA,iBAAA,QACA,aAAA,QpB+rGF,mBoB7rGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpB+rGJ,oBoB7rGE,oBpB8rGF,mCoB3rGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpBqsGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoB/rGI,0BpBosGJ,yCAHA,yCAHA,yCoB3rGM,MAAA,KACA,iBAAA,QACA,aAAA,QpB0sGN,4BAHA,4BoBjsGI,4BpBqsGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoB7rGM,iBAAA,QACA,aAAA,QD8BN,oBCzBI,MAAA,QACA,iBAAA,KD4BJ,UCxEE,MAAA,KACA,iBAAA,QACA,aAAA,QpBovGF,gBoBlvGE,gBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,gBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpBovGJ,iBoBlvGE,iBpBmvGF,gCoBhvGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpB0vGJ,uBAHA,uBAHA,uBAKA,uBAHA,uBoBpvGI,uBpByvGJ,sCAHA,sCAHA,sCoBhvGM,MAAA,KACA,iBAAA,QACA,aAAA,QpB+vGN,yBAHA,yBoBtvGI,yBpB0vGJ,0BAHA,0BAHA,0BAOA,mCAHA,mCAHA,mCoBlvGM,iBAAA,QACA,aAAA,QDkCN,iBC7BI,MAAA,QACA,iBAAA,KDgCJ,aC5EE,MAAA,KACA,iBAAA,QACA,aAAA,QpByyGF,mBoBvyGE,mBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,mBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpByyGJ,oBoBvyGE,oBpBwyGF,mCoBryGI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpB+yGJ,0BAHA,0BAHA,0BAKA,0BAHA,0BoBzyGI,0BpB8yGJ,yCAHA,yCAHA,yCoBryGM,MAAA,KACA,iBAAA,QACA,aAAA,QpBozGN,4BAHA,4BoB3yGI,4BpB+yGJ,6BAHA,6BAHA,6BAOA,sCAHA,sCAHA,sCoBvyGM,iBAAA,QACA,aAAA,QDsCN,oBCjCI,MAAA,QACA,iBAAA,KDoCJ,YChFE,MAAA,KACA,iBAAA,QACA,aAAA,QpB81GF,kBoB51GE,kBAEE,MAAA,KACA,iBAAA,QACA,aAAA,QAEF,kBACE,MAAA,KACA,iBAAA,QACA,aAAA,QpB81GJ,mBoB51GE,mBpB61GF,kCoB11GI,MAAA,KACA,iBAAA,QACA,iBAAA,KACA,aAAA,QpBo2GJ,yBAHA,yBAHA,yBAKA,yBAHA,yBoB91GI,yBpBm2GJ,wCAHA,wCAHA,wCoB11GM,MAAA,KACA,iBAAA,QACA,aAAA,QpBy2GN,2BAHA,2BoBh2GI,2BpBo2GJ,4BAHA,4BAHA,4BAOA,qCAHA,qCAHA,qCoB51GM,iBAAA,QACA,aAAA,QD0CN,mBCrCI,MAAA,QACA,iBAAA,KD6CJ,UACE,YAAA,IACA,MAAA,QACA,cAAA,EAEA,UnBwzGF,iBADA,iBAEA,oBACA,6BmBrzGI,iBAAA,YfnCF,mBAAA,KACQ,WAAA,KeqCR,UnB0zGF,iBADA,gBADA,gBmBpzGI,aAAA,YnB0zGJ,gBmBxzGE,gBAEE,MAAA,QACA,gBAAA,UACA,iBAAA,YnB2zGJ,0BmBvzGI,0BnBwzGJ,mCAFA,mCmBpzGM,MAAA,KACA,gBAAA,KnB0zGN,mBmBjzGA,QC9EE,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IpBm4GF,mBmBpzGA,QClFE,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IpB04GF,mBmBvzGA,QCtFE,QAAA,IAAA,IACA,UAAA,KACA,YAAA,IACA,cAAA,ID2FF,WACE,QAAA,MACA,MAAA,KAIF,sBACE,WAAA,InBuzGF,6BADA,4BmB/yGE,6BACE,MAAA,KG1JJ,MACE,QAAA,ElBoLA,mBAAA,QAAA,KAAA,OACK,cAAA,QAAA,KAAA,OACG,WAAA,QAAA,KAAA,OkBnLR,SACE,QAAA,EAIJ,UACE,QAAA,KAEA,aAAY,QAAA,MACZ,eAAY,QAAA,UACZ,kBAAY,QAAA,gBAGd,YACE,SAAA,SACA,OAAA,EACA,SAAA,OlBsKA,4BAAA,MAAA,CAAA,WACQ,uBAAA,MAAA,CAAA,WAAA,oBAAA,MAAA,CAAA,WAOR,4BAAA,KACQ,uBAAA,KAAA,oBAAA,KAGR,mCAAA,KACQ,8BAAA,KAAA,2BAAA,KmB5MV,OACE,QAAA,aACA,MAAA,EACA,OAAA,EACA,YAAA,IACA,eAAA,OACA,WAAA,IAAA,OACA,WAAA,IAAA,QACA,aAAA,IAAA,MAAA,YACA,YAAA,IAAA,MAAA,YvBu/GF,UuBn/GA,QAEE,SAAA,SAIF,uBACE,QAAA,EAIF,eACE,SAAA,SACA,IAAA,KACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,MAAA,KACA,UAAA,MACA,QAAA,IAAA,EACA,OAAA,IAAA,EAAA,EACA,UAAA,KACA,WAAA,KACA,WAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,KACA,OAAA,IAAA,MAAA,gBACA,cAAA,InBuBA,mBAAA,EAAA,IAAA,KAAA,iBACQ,WAAA,EAAA,IAAA,KAAA,iBmBlBR,0BACE,MAAA,EACA,KAAA,KAzBJ,wBCzBE,OAAA,IACA,OAAA,IAAA,EACA,SAAA,OACA,iBAAA,QDsBF,oBAmCI,QAAA,MACA,QAAA,IAAA,KACA,MAAA,KACA,YAAA,IACA,YAAA,WACA,MAAA,KACA,YAAA,OvB8+GJ,0BuB5+GI,0BAEE,MAAA,QACA,gBAAA,KACA,iBAAA,QAOJ,yBvBw+GF,+BADA,+BuBp+GI,MAAA,KACA,gBAAA,KACA,iBAAA,QACA,QAAA,EASF,2BvBi+GF,iCADA,iCuB79GI,MAAA,KvBk+GJ,iCuB99GE,iCAEE,gBAAA,KACA,OAAA,YACA,iBAAA,YACA,iBAAA,KEzGF,OAAA,0DF+GF,qBAGI,QAAA,MAHJ,QAQI,QAAA,EAQJ,qBACE,MAAA,EACA,KAAA,KAQF,oBACE,MAAA,KACA,KAAA,EAIF,iBACE,QAAA,MACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,WACA,MAAA,KACA,YAAA,OAIF,mBACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,IAIF,2BACE,MAAA,EACA,KAAA,KAQF,evB+7GA,sCuB37GI,QAAA,GACA,WAAA,EACA,cAAA,IAAA,OACA,cAAA,IAAA,QAPJ,uBvBs8GA,8CuB37GI,IAAA,KACA,OAAA,KACA,cAAA,IASJ,yBACE,6BApEA,MAAA,EACA,KAAA,KAmEA,kCA1DA,MAAA,KACA,KAAA,GG1IF,W1BkoHA,oB0BhoHE,SAAA,SACA,QAAA,aACA,eAAA,O1BooHF,yB0BxoHA,gBAMI,SAAA,SACA,MAAA,K1B4oHJ,gCAFA,gCAFA,+BAFA,+BAKA,uBAFA,uBAFA,sB0BroHI,sBAIE,QAAA,EAMN,qB1BooHA,2BACA,2BACA,iC0BjoHI,YAAA,KAKJ,aACE,YAAA,KADF,kB1BmoHA,wBACA,0B0B7nHI,MAAA,KAPJ,kB1BwoHA,wBACA,0B0B7nHI,YAAA,IAIJ,yEACE,cAAA,EAIF,4BACE,YAAA,EACA,mECpDA,wBAAA,EACA,2BAAA,EDwDF,6C1B2nHA,8C2B5qHE,uBAAA,EACA,0BAAA,EDsDF,sBACE,MAAA,KAEF,8DACE,cAAA,EAEF,mE1B0nHA,oE2B/rHE,wBAAA,EACA,2BAAA,ED0EF,oECnEE,uBAAA,EACA,0BAAA,EDuEF,mC1BwnHA,iC0BtnHE,QAAA,EAiBF,iCACE,cAAA,IACA,aAAA,IAEF,oCACE,cAAA,KACA,aAAA,KAKF,iCtB/CE,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBsBkDR,0CtBnDA,mBAAA,KACQ,WAAA,KsByDV,YACE,YAAA,EAGF,eACE,aAAA,IAAA,IAAA,EACA,oBAAA,EAGF,uBACE,aAAA,EAAA,IAAA,IAOF,yB1B4lHA,+BACA,oC0BzlHI,QAAA,MACA,MAAA,KACA,MAAA,KACA,UAAA,KAPJ,oCAcM,MAAA,KAdN,8B1BumHA,oCACA,oCACA,0C0BnlHI,WAAA,KACA,YAAA,EAKF,4DACE,cAAA,EAEF,sDC7KA,uBAAA,IACA,wBAAA,IAOA,2BAAA,EACA,0BAAA,EDwKA,sDCjLA,uBAAA,EACA,wBAAA,EAOA,2BAAA,IACA,0BAAA,ID6KF,uEACE,cAAA,EAEF,4E1BqlHA,6E2BtwHE,2BAAA,EACA,0BAAA,EDsLF,6EC/LE,uBAAA,EACA,wBAAA,EDsMF,qBACE,QAAA,MACA,MAAA,KACA,aAAA,MACA,gBAAA,SAJF,0B1BslHA,gC0B/kHI,QAAA,WACA,MAAA,KACA,MAAA,GATJ,qCAYI,MAAA,KAZJ,+CAgBI,KAAA,K1BmlHJ,gD0BlkHA,6C1BmkHA,2DAFA,wD0B5jHM,SAAA,SACA,KAAA,cACA,eAAA,KE1ON,aACE,SAAA,SACA,QAAA,MACA,gBAAA,SAGA,0BACE,MAAA,KACA,cAAA,EACA,aAAA,EATJ,2BAeI,SAAA,SACA,QAAA,EAKA,MAAA,KAEA,MAAA,KACA,cAAA,EAEA,iCACE,QAAA,EAUN,8B5B2xHA,mCACA,sCkBpwHE,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UACA,cAAA,IAEA,oClBswHF,yCACA,4CkBtwHI,OAAA,KACA,YAAA,KlB4wHJ,8CACA,mDACA,sDkB3wHE,sClBuwHF,2CACA,8CkBtwHI,OAAA,KUhCJ,8B5B6yHA,mCACA,sCkB3xHE,OAAA,KACA,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,cAAA,IAEA,oClB6xHF,yCACA,4CkB7xHI,OAAA,KACA,YAAA,KlBmyHJ,8CACA,mDACA,sDkBlyHE,sClB8xHF,2CACA,8CkB7xHI,OAAA,KlBqyHJ,2B4B5zHA,mB5B2zHA,iB4BxzHE,QAAA,W5B8zHF,8D4B5zHE,sD5B2zHF,oD4B1zHI,cAAA,EAIJ,mB5B2zHA,iB4BzzHE,MAAA,GACA,YAAA,OACA,eAAA,OAKF,mBACE,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,IAGA,4BACE,QAAA,IAAA,KACA,UAAA,KACA,cAAA,IAEF,4BACE,QAAA,KAAA,KACA,UAAA,KACA,cAAA,I5ByzHJ,wC4B70HA,qCA0BI,WAAA,EAKJ,uC5BkzHA,+BACA,kCACA,6CACA,8CAEA,6DADA,wE2B55HE,wBAAA,EACA,2BAAA,EC8GF,+BACE,aAAA,EAEF,sC5BmzHA,8BAKA,+DADA,oDAHA,iCACA,4CACA,6C2Bh6HE,uBAAA,EACA,0BAAA,ECkHF,8BACE,YAAA,EAKF,iBACE,SAAA,SAGA,UAAA,EACA,YAAA,OALF,sBAUI,SAAA,SAVJ,2BAYM,YAAA,K5BizHN,6BADA,4B4B7yHI,4BAGE,QAAA,EAKJ,kC5B0yHF,wC4BvyHM,aAAA,KAGJ,iC5BwyHF,uC4BryHM,QAAA,EACA,YAAA,KC/JN,KACE,aAAA,EACA,cAAA,EACA,WAAA,KAHF,QAOI,SAAA,SACA,QAAA,MARJ,UAWM,SAAA,SACA,QAAA,MACA,QAAA,KAAA,K7By8HN,gB6Bx8HM,gBAEE,gBAAA,KACA,iBAAA,KAKJ,mBACE,MAAA,K7Bu8HN,yB6Br8HM,yBAEE,MAAA,KACA,gBAAA,KACA,OAAA,YACA,iBAAA,YAOJ,a7Bi8HJ,mBADA,mB6B77HM,iBAAA,KACA,aAAA,QAzCN,kBLLE,OAAA,IACA,OAAA,IAAA,EACA,SAAA,OACA,iBAAA,QKEF,cA0DI,UAAA,KASJ,UACE,cAAA,IAAA,MAAA,KADF,aAGI,MAAA,KAEA,cAAA,KALJ,eASM,aAAA,IACA,YAAA,WACA,OAAA,IAAA,MAAA,YACA,cAAA,IAAA,IAAA,EAAA,EACA,qBACE,aAAA,KAAA,KAAA,KAMF,sB7B86HN,4BADA,4B6B16HQ,MAAA,KACA,OAAA,QACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,oBAAA,YAKN,wBAqDA,MAAA,KA8BA,cAAA,EAnFA,2BAwDE,MAAA,KAxDF,6BA0DI,cAAA,IACA,WAAA,OA3DJ,iDAgEE,IAAA,KACA,KAAA,KAGF,yBAAA,2BAEI,QAAA,WACA,MAAA,GAHJ,6BAKM,cAAA,GAzEN,6BAuFE,aAAA,EACA,cAAA,IAxFF,kC7Bu8HF,wCADA,wC6Bx2HI,OAAA,IAAA,MAAA,KAGF,yBAAA,6BAEI,cAAA,IAAA,MAAA,KACA,cAAA,IAAA,IAAA,EAAA,EAHJ,kC7Bg3HA,wCADA,wC6Bv2HI,oBAAA,MAhGN,cAEI,MAAA,KAFJ,gBAMM,cAAA,IANN,iBASM,YAAA,IAKA,uB7By8HN,6BADA,6B6Br8HQ,MAAA,KACA,iBAAA,QAQR,gBAEI,MAAA,KAFJ,mBAIM,WAAA,IACA,YAAA,EAYN,eACE,MAAA,KADF,kBAII,MAAA,KAJJ,oBAMM,cAAA,IACA,WAAA,OAPN,wCAYI,IAAA,KACA,KAAA,KAGF,yBAAA,kBAEI,QAAA,WACA,MAAA,GAHJ,oBAKM,cAAA,GASR,oBACE,cAAA,EADF,yBAKI,aAAA,EACA,cAAA,IANJ,8B7By7HA,oCADA,oC6B56HI,OAAA,IAAA,MAAA,KAGF,yBAAA,yBAEI,cAAA,IAAA,MAAA,KACA,cAAA,IAAA,IAAA,EAAA,EAHJ,8B7Bo7HA,oCADA,oC6B36HI,oBAAA,MAUN,uBAEI,QAAA,KAFJ,qBAKI,QAAA,MASJ,yBAEE,WAAA,KF7OA,uBAAA,EACA,wBAAA,EGQF,QACE,SAAA,SACA,WAAA,KACA,cAAA,KACA,OAAA,IAAA,MAAA,YAKA,yBAAA,QACE,cAAA,KAaF,yBAAA,eACE,MAAA,MAeJ,iBACE,cAAA,KACA,aAAA,KACA,WAAA,QACA,WAAA,IAAA,MAAA,YACA,mBAAA,MAAA,EAAA,IAAA,EAAA,qBAAA,WAAA,MAAA,EAAA,IAAA,EAAA,qBAEA,2BAAA,MAEA,oBACE,WAAA,KAGF,yBAAA,iBACE,MAAA,KACA,WAAA,EACA,mBAAA,KAAA,WAAA,KAEA,0BACE,QAAA,gBACA,OAAA,eACA,eAAA,EACA,SAAA,kBAGF,oBACE,WAAA,Q9BknIJ,sC8B7mIE,mC9B4mIF,oC8BzmII,cAAA,EACA,aAAA,G9B+mIN,qB8B1mIA,kBAWE,SAAA,MACA,MAAA,EACA,KAAA,EACA,QAAA,K9BmmIF,sC8BjnIA,mCAGI,WAAA,MAEA,4D9BinIF,sC8BjnIE,mCACE,WAAA,OAWJ,yB9B2mIA,qB8B3mIA,kBACE,cAAA,GAIJ,kBACE,IAAA,EACA,aAAA,EAAA,EAAA,IAEF,qBACE,OAAA,EACA,cAAA,EACA,aAAA,IAAA,EAAA,E9B+mIF,kCAFA,gCACA,4B8BtmIA,0BAII,aAAA,MACA,YAAA,MAEA,yB9BwmIF,kCAFA,gCACA,4B8BvmIE,0BACE,aAAA,EACA,YAAA,GAaN,mBACE,QAAA,KACA,aAAA,EAAA,EAAA,IAEA,yBAAA,mBACE,cAAA,GAOJ,cACE,MAAA,KACA,OAAA,KACA,QAAA,KAAA,KACA,UAAA,KACA,YAAA,K9B8lIF,oB8B5lIE,oBAEE,gBAAA,KATJ,kBAaI,QAAA,MAGF,yBACE,iC9B0lIF,uC8BxlII,YAAA,OAWN,eACE,SAAA,SACA,MAAA,MACA,QAAA,IAAA,KACA,aAAA,KC9LA,WAAA,IACA,cAAA,ID+LA,iBAAA,YACA,iBAAA,KACA,OAAA,IAAA,MAAA,YACA,cAAA,IAIA,qBACE,QAAA,EAdJ,yBAmBI,QAAA,MACA,MAAA,KACA,OAAA,IACA,cAAA,IAtBJ,mCAyBI,WAAA,IAGF,yBAAA,eACE,QAAA,MAUJ,YACE,OAAA,MAAA,MADF,iBAII,YAAA,KACA,eAAA,KACA,YAAA,KAGF,yBAAA,iCAGI,SAAA,OACA,MAAA,KACA,MAAA,KACA,WAAA,EACA,iBAAA,YACA,OAAA,EACA,mBAAA,KAAA,WAAA,K9BykIJ,kD8BllIA,sCAYM,QAAA,IAAA,KAAA,IAAA,KAZN,sCAeM,YAAA,K9B0kIN,4C8BzkIM,4CAEE,iBAAA,MAOR,yBAAA,YACE,MAAA,KACA,OAAA,EAFF,eAKI,MAAA,KALJ,iBAOM,YAAA,KACA,eAAA,MAYR,aACE,QAAA,KAAA,KACA,aAAA,MACA,YAAA,MACA,WAAA,IAAA,MAAA,YACA,cAAA,IAAA,MAAA,Y1B5NA,mBAAA,MAAA,EAAA,IAAA,EAAA,oBAAA,CAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,oBAAA,CAAA,EAAA,IAAA,EAAA,qB2BjER,WAAA,IACA,cAAA,Id6cA,yBAAA,yBAGI,QAAA,aACA,cAAA,EACA,eAAA,OALJ,2BAUI,QAAA,aACA,MAAA,KACA,eAAA,OAZJ,kCAiBI,QAAA,aAjBJ,0BAqBI,QAAA,aACA,eAAA,OjB+4HJ,wCiBr6HA,6CjBo6HA,2CiBz4HM,MAAA,KA3BN,wCAiCI,MAAA,KAjCJ,4BAqCI,cAAA,EACA,eAAA,OjB04HJ,uBiBh7HA,oBA6CI,QAAA,aACA,WAAA,EACA,cAAA,EACA,eAAA,OjBu4HJ,6BiBv7HA,0BAmDM,aAAA,EjBw4HN,4CiB37HA,sCAwDI,SAAA,SACA,YAAA,EAzDJ,kDA8DI,IAAA,GaxOF,yBAAA,yBACE,cAAA,IAEA,oCACE,cAAA,GASN,yBAAA,aACE,MAAA,KACA,YAAA,EACA,eAAA,EACA,aAAA,EACA,YAAA,EACA,OAAA,E1BvPF,mBAAA,KACQ,WAAA,M0B+PV,8BACE,WAAA,EHpUA,uBAAA,EACA,wBAAA,EGuUF,mDACE,cAAA,EHzUA,uBAAA,IACA,wBAAA,IAOA,2BAAA,EACA,0BAAA,EG0UF,YChVE,WAAA,IACA,cAAA,IDkVA,mBCnVA,WAAA,KACA,cAAA,KDqVA,mBCtVA,WAAA,KACA,cAAA,KD+VF,aChWE,WAAA,KACA,cAAA,KDkWA,yBAAA,aACE,MAAA,KACA,aAAA,KACA,YAAA,MAaJ,yBACE,aEtWA,MAAA,eFuWA,cE1WA,MAAA,gBF4WE,aAAA,MAFF,4BAKI,aAAA,GAUN,gBACE,iBAAA,QACA,aAAA,QAFF,8BAKI,MAAA,K9BmlIJ,oC8BllII,oCAEE,MAAA,QACA,iBAAA,YATN,6BAcI,MAAA,KAdJ,iCAmBM,MAAA,K9BglIN,uC8B9kIM,uCAEE,MAAA,KACA,iBAAA,YAIF,sC9B6kIN,4CADA,4C8BzkIQ,MAAA,KACA,iBAAA,QAIF,wC9B2kIN,8CADA,8C8BvkIQ,MAAA,KACA,iBAAA,YAOF,oC9BskIN,0CADA,0C8BlkIQ,MAAA,KACA,iBAAA,QAIJ,yBAAA,sDAIM,MAAA,K9BmkIR,4D8BlkIQ,4DAEE,MAAA,KACA,iBAAA,YAIF,2D9BikIR,iEADA,iE8B7jIU,MAAA,KACA,iBAAA,QAIF,6D9B+jIR,mEADA,mE8B3jIU,MAAA,KACA,iBAAA,aA/EZ,+BAuFI,aAAA,K9B4jIJ,qC8B3jII,qCAEE,iBAAA,KA1FN,yCA6FM,iBAAA,KA7FN,iC9B0pIA,6B8BvjII,aAAA,QAnGJ,6BA4GI,MAAA,KACA,mCACE,MAAA,KA9GN,0BAmHI,MAAA,K9BojIJ,gC8BnjII,gCAEE,MAAA,K9BsjIN,0C8BljIM,0C9BmjIN,mDAFA,mD8B/iIQ,MAAA,KAQR,gBACE,iBAAA,KACA,aAAA,QAFF,8BAKI,MAAA,Q9B+iIJ,oC8B9iII,oCAEE,MAAA,KACA,iBAAA,YATN,6BAcI,MAAA,QAdJ,iCAmBM,MAAA,Q9B4iIN,uC8B1iIM,uCAEE,MAAA,KACA,iBAAA,YAIF,sC9ByiIN,4CADA,4C8BriIQ,MAAA,KACA,iBAAA,QAIF,wC9BuiIN,8CADA,8C8BniIQ,MAAA,KACA,iBAAA,YAMF,oC9BmiIN,0CADA,0C8B/hIQ,MAAA,KACA,iBAAA,QAIJ,yBAAA,kEAIM,aAAA,QAJN,0DAOM,iBAAA,QAPN,sDAUM,MAAA,Q9BgiIR,4D8B/hIQ,4DAEE,MAAA,KACA,iBAAA,YAIF,2D9B8hIR,iEADA,iE8B1hIU,MAAA,KACA,iBAAA,QAIF,6D9B4hIR,mEADA,mE8BxhIU,MAAA,KACA,iBAAA,aApFZ,+BA6FI,aAAA,K9BwhIJ,qC8BvhII,qCAEE,iBAAA,KAhGN,yCAmGM,iBAAA,KAnGN,iC9B4nIA,6B8BnhII,aAAA,QAzGJ,6BA6GI,MAAA,QACA,mCACE,MAAA,KA/GN,0BAoHI,MAAA,Q9BqhIJ,gC8BphII,gCAEE,MAAA,K9BuhIN,0C8BnhIM,0C9BohIN,mDAFA,mD8BhhIQ,MAAA,KGtoBR,YACE,QAAA,IAAA,KACA,cAAA,KACA,WAAA,KACA,iBAAA,QACA,cAAA,IALF,eAQI,QAAA,aARJ,yBAWM,QAAA,EAAA,IACA,MAAA,KACA,QAAA,SAbN,oBAkBI,MAAA,KCpBJ,YACE,QAAA,aACA,aAAA,EACA,OAAA,KAAA,EACA,cAAA,IAJF,eAOI,QAAA,OAPJ,iBlCyrJA,oBkC/qJM,SAAA,SACA,MAAA,KACA,QAAA,IAAA,KACA,YAAA,KACA,YAAA,WACA,MAAA,QACA,gBAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KlCorJN,uBkClrJM,uBlCmrJN,0BAFA,0BkC/qJQ,QAAA,EACA,MAAA,QACA,iBAAA,KACA,aAAA,KAGJ,6BlCkrJJ,gCkC/qJQ,YAAA,EPnBN,uBAAA,IACA,0BAAA,IOsBE,4BlCirJJ,+B2BhtJE,wBAAA,IACA,2BAAA,IOwCE,sBlC+qJJ,4BAFA,4BADA,yBAIA,+BAFA,+BkC3qJM,QAAA,EACA,MAAA,KACA,OAAA,QACA,iBAAA,QACA,aAAA,QlCmrJN,wBAEA,8BADA,8BkCxuJA,2BlCsuJA,iCADA,iCkCtqJM,MAAA,KACA,OAAA,YACA,iBAAA,KACA,aAAA,KASN,oBlCqqJA,uBmC7uJM,QAAA,KAAA,KACA,UAAA,KACA,YAAA,UAEF,gCnC+uJJ,mC2B1uJE,uBAAA,IACA,0BAAA,IQAE,+BnC8uJJ,kC2BvvJE,wBAAA,IACA,2BAAA,IO2EF,oBlCgrJA,uBmC7vJM,QAAA,IAAA,KACA,UAAA,KACA,YAAA,IAEF,gCnC+vJJ,mC2B1vJE,uBAAA,IACA,0BAAA,IQAE,+BnC8vJJ,kC2BvwJE,wBAAA,IACA,2BAAA,ISHF,OACE,aAAA,EACA,OAAA,KAAA,EACA,WAAA,OACA,WAAA,KAJF,UAOI,QAAA,OAPJ,YpCuxJA,eoC7wJM,QAAA,aACA,QAAA,IAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,KpCixJN,kBoC/xJA,kBAmBM,gBAAA,KACA,iBAAA,KApBN,epCoyJA,kBoCzwJM,MAAA,MA3BN,mBpCwyJA,sBoCtwJM,MAAA,KAlCN,mBpC6yJA,yBADA,yBAEA,sBoCnwJM,MAAA,KACA,OAAA,YACA,iBAAA,KC9CN,OACE,QAAA,OACA,QAAA,KAAA,KAAA,KACA,UAAA,IACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,eAAA,SACA,cAAA,MrCuzJF,cqCnzJI,cAEE,MAAA,KACA,gBAAA,KACA,OAAA,QAKJ,aACE,QAAA,KAIF,YACE,SAAA,SACA,IAAA,KAOJ,eCtCE,iBAAA,KtCk1JF,2BsC/0JI,2BAEE,iBAAA,QDqCN,eC1CE,iBAAA,QtCy1JF,2BsCt1JI,2BAEE,iBAAA,QDyCN,eC9CE,iBAAA,QtCg2JF,2BsC71JI,2BAEE,iBAAA,QD6CN,YClDE,iBAAA,QtCu2JF,wBsCp2JI,wBAEE,iBAAA,QDiDN,eCtDE,iBAAA,QtC82JF,2BsC32JI,2BAEE,iBAAA,QDqDN,cC1DE,iBAAA,QtCq3JF,0BsCl3JI,0BAEE,iBAAA,QCFN,OACE,QAAA,aACA,UAAA,KACA,QAAA,IAAA,IACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,WAAA,OACA,YAAA,OACA,eAAA,OACA,iBAAA,KACA,cAAA,KAGA,aACE,QAAA,KAIF,YACE,SAAA,SACA,IAAA,KvCq3JJ,0BuCl3JE,eAEE,IAAA,EACA,QAAA,IAAA,IvCo3JJ,cuC/2JI,cAEE,MAAA,KACA,gBAAA,KACA,OAAA,QAKJ,+BvC42JF,4BuC12JI,MAAA,QACA,iBAAA,KAGF,wBACE,MAAA,MAGF,+BACE,aAAA,IAGF,uBACE,YAAA,IC1DJ,WACE,YAAA,KACA,eAAA,KACA,cAAA,KACA,MAAA,QACA,iBAAA,KxCu6JF,ewC56JA,cASI,MAAA,QATJ,aAaI,cAAA,KACA,UAAA,KACA,YAAA,IAfJ,cAmBI,iBAAA,QAGF,sBxCk6JF,4BwCh6JI,cAAA,KACA,aAAA,KACA,cAAA,IA1BJ,sBA8BI,UAAA,KAGF,oCAAA,WACE,YAAA,KACA,eAAA,KAEA,sBxCi6JF,4BwC/5JI,cAAA,KACA,aAAA,KxCm6JJ,ewC16JA,cAYI,UAAA,MC1CN,WACE,QAAA,MACA,QAAA,IACA,cAAA,KACA,YAAA,WACA,iBAAA,KACA,OAAA,IAAA,MAAA,KACA,cAAA,IrCiLA,mBAAA,OAAA,IAAA,YACK,cAAA,OAAA,IAAA,YACG,WAAA,OAAA,IAAA,YJ+xJV,iByCz9JA,eAaI,aAAA,KACA,YAAA,KzCi9JJ,mBADA,kByC58JE,kBAGE,aAAA,QArBJ,oBA0BI,QAAA,IACA,MAAA,KC3BJ,OACE,QAAA,KACA,cAAA,KACA,OAAA,IAAA,MAAA,YACA,cAAA,IAJF,UAQI,WAAA,EACA,MAAA,QATJ,mBAcI,YAAA,IAdJ,S1Co/JA,U0Ch+JI,cAAA,EApBJ,WAwBI,WAAA,IASJ,mB1C09JA,mB0Cx9JE,cAAA,KAFF,0B1C89JA,0B0Cx9JI,SAAA,SACA,IAAA,KACA,MAAA,MACA,MAAA,QAQJ,eCvDE,MAAA,QACA,iBAAA,QACA,aAAA,QDqDF,kBClDI,iBAAA,QDkDJ,2BC9CI,MAAA,QDkDJ,YC3DE,MAAA,QACA,iBAAA,QACA,aAAA,QDyDF,eCtDI,iBAAA,QDsDJ,wBClDI,MAAA,QDsDJ,eC/DE,MAAA,QACA,iBAAA,QACA,aAAA,QD6DF,kBC1DI,iBAAA,QD0DJ,2BCtDI,MAAA,QD0DJ,cCnEE,MAAA,QACA,iBAAA,QACA,aAAA,QDiEF,iBC9DI,iBAAA,QD8DJ,0BC1DI,MAAA,QCDJ,wCACE,KAAQ,oBAAA,KAAA,EACR,GAAQ,oBAAA,EAAA,GAIV,mCACE,KAAQ,oBAAA,KAAA,EACR,GAAQ,oBAAA,EAAA,GAFV,gCACE,KAAQ,oBAAA,KAAA,EACR,GAAQ,oBAAA,EAAA,GAQV,UACE,OAAA,KACA,cAAA,KACA,SAAA,OACA,iBAAA,QACA,cAAA,IxCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,eACQ,WAAA,MAAA,EAAA,IAAA,IAAA,ewClCV,cACE,MAAA,KACA,MAAA,GACA,OAAA,KACA,UAAA,KACA,YAAA,KACA,MAAA,KACA,WAAA,OACA,iBAAA,QxCyBA,mBAAA,MAAA,EAAA,KAAA,EAAA,gBACQ,WAAA,MAAA,EAAA,KAAA,EAAA,gBAyHR,mBAAA,MAAA,IAAA,KACK,cAAA,MAAA,IAAA,KACG,WAAA,MAAA,IAAA,KJw6JV,sB4CnjKA,gCCDI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKDEF,wBAAA,KAAA,KAAA,gBAAA,KAAA,K5CwjKF,qB4CjjKA,+BxC5CE,kBAAA,qBAAA,GAAA,OAAA,SACK,aAAA,qBAAA,GAAA,OAAA,SACG,UAAA,qBAAA,GAAA,OAAA,SwCmDV,sBEvEE,iBAAA,QAGA,wCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKDsBJ,mBE3EE,iBAAA,QAGA,qCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKD0BJ,sBE/EE,iBAAA,QAGA,wCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKD8BJ,qBEnFE,iBAAA,QAGA,uCDgDE,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKExDJ,OAEE,WAAA,KAEA,mBACE,WAAA,EAIJ,O/CqpKA,Y+CnpKE,SAAA,OACA,KAAA,EAGF,YACE,MAAA,QAGF,cACE,QAAA,MAGA,4BACE,UAAA,KAIJ,a/CgpKA,mB+C9oKE,aAAA,KAGF,Y/C+oKA,kB+C7oKE,cAAA,K/CkpKF,Y+C/oKA,Y/C8oKA,a+C3oKE,QAAA,WACA,eAAA,IAGF,cACE,eAAA,OAGF,cACE,eAAA,OAIF,eACE,WAAA,EACA,cAAA,IAMF,YACE,aAAA,EACA,WAAA,KCrDF,YAEE,aAAA,EACA,cAAA,KAQF,iBACE,SAAA,SACA,QAAA,MACA,QAAA,KAAA,KAEA,cAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,KAGA,6BrB7BA,uBAAA,IACA,wBAAA,IqB+BA,4BACE,cAAA,ErBzBF,2BAAA,IACA,0BAAA,IqB6BA,0BhDqrKF,gCADA,gCgDjrKI,MAAA,KACA,OAAA,YACA,iBAAA,KALF,mDhD4rKF,yDADA,yDgDlrKM,MAAA,QATJ,gDhDisKF,sDADA,sDgDprKM,MAAA,KAKJ,wBhDqrKF,8BADA,8BgDjrKI,QAAA,EACA,MAAA,KACA,iBAAA,QACA,aAAA,QANF,iDhDisKF,wDAHA,uDADA,uDAMA,8DAHA,6DAJA,uDAMA,8DAHA,6DgDnrKM,MAAA,QAZJ,8ChDwsKF,oDADA,oDgDxrKM,MAAA,QAWN,kBhDkrKA,uBgDhrKE,MAAA,KAFF,2ChDsrKA,gDgDjrKI,MAAA,KhDsrKJ,wBgDlrKE,wBhDmrKF,6BAFA,6BgD/qKI,MAAA,KACA,gBAAA,KACA,iBAAA,QAIJ,uBACE,MAAA,KACA,WAAA,KnCvGD,yBoCIG,MAAA,QACA,iBAAA,QAEA,0BjDuxKJ,+BiDrxKM,MAAA,QAFF,mDjD2xKJ,wDiDtxKQ,MAAA,QjD2xKR,gCiDxxKM,gCjDyxKN,qCAFA,qCiDrxKQ,MAAA,QACA,iBAAA,QAEF,iCjD4xKN,uCAFA,uCADA,sCAIA,4CAFA,4CiDxxKQ,MAAA,KACA,iBAAA,QACA,aAAA,QpCzBP,sBoCIG,MAAA,QACA,iBAAA,QAEA,uBjDozKJ,4BiDlzKM,MAAA,QAFF,gDjDwzKJ,qDiDnzKQ,MAAA,QjDwzKR,6BiDrzKM,6BjDszKN,kCAFA,kCiDlzKQ,MAAA,QACA,iBAAA,QAEF,8BjDyzKN,oCAFA,oCADA,mCAIA,yCAFA,yCiDrzKQ,MAAA,KACA,iBAAA,QACA,aAAA,QpCzBP,yBoCIG,MAAA,QACA,iBAAA,QAEA,0BjDi1KJ,+BiD/0KM,MAAA,QAFF,mDjDq1KJ,wDiDh1KQ,MAAA,QjDq1KR,gCiDl1KM,gCjDm1KN,qCAFA,qCiD/0KQ,MAAA,QACA,iBAAA,QAEF,iCjDs1KN,uCAFA,uCADA,sCAIA,4CAFA,4CiDl1KQ,MAAA,KACA,iBAAA,QACA,aAAA,QpCzBP,wBoCIG,MAAA,QACA,iBAAA,QAEA,yBjD82KJ,8BiD52KM,MAAA,QAFF,kDjDk3KJ,uDiD72KQ,MAAA,QjDk3KR,+BiD/2KM,+BjDg3KN,oCAFA,oCiD52KQ,MAAA,QACA,iBAAA,QAEF,gCjDm3KN,sCAFA,sCADA,qCAIA,2CAFA,2CiD/2KQ,MAAA,KACA,iBAAA,QACA,aAAA,QDiGR,yBACE,WAAA,EACA,cAAA,IAEF,sBACE,cAAA,EACA,YAAA,IExHF,OACE,cAAA,KACA,iBAAA,KACA,OAAA,IAAA,MAAA,YACA,cAAA,I9C0DA,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gB8CtDV,YACE,QAAA,KAKF,eACE,QAAA,KAAA,KACA,cAAA,IAAA,MAAA,YvBtBA,uBAAA,IACA,wBAAA,IuBmBF,0CAMI,MAAA,QAKJ,aACE,WAAA,EACA,cAAA,EACA,UAAA,KACA,MAAA,QlD24KF,oBAEA,sBkDj5KA,elD84KA,mBAEA,qBkDr4KI,MAAA,QAKJ,cACE,QAAA,KAAA,KACA,iBAAA,QACA,WAAA,IAAA,MAAA,KvB1CA,2BAAA,IACA,0BAAA,IuBmDF,mBlD+3KA,mCkD53KI,cAAA,EAHJ,oClDm4KA,oDkD73KM,aAAA,IAAA,EACA,cAAA,EAIF,4DlD63KJ,4EkD33KQ,WAAA,EvBzEN,uBAAA,IACA,wBAAA,IuB8EE,0DlD23KJ,0EkDz3KQ,cAAA,EvBzEN,2BAAA,IACA,0BAAA,IuBmDF,+EvB5DE,uBAAA,EACA,wBAAA,EuB4FF,wDAEI,iBAAA,EAGJ,0BACE,iBAAA,ElDw3KF,8BkDh3KA,clD+2KA,gCkD32KI,cAAA,ElDi3KJ,sCkDr3KA,sBlDo3KA,wCkD72KM,cAAA,KACA,aAAA,KlDk3KN,wDkD13KA,0BvB3GE,uBAAA,IACA,wBAAA,I3B2+KF,yFAFA,yFACA,2DkDh4KA,2DAmBQ,uBAAA,IACA,wBAAA,IlDo3KR,wGAIA,wGANA,wGAIA,wGAHA,0EAIA,0EkD34KA,0ElDy4KA,0EkDj3KU,uBAAA,IlD03KV,uGAIA,uGANA,uGAIA,uGAHA,yEAIA,yEkDr5KA,yElDm5KA,yEkDv3KU,wBAAA,IlD83KV,sDkD15KA,yBvBnGE,2BAAA,IACA,0BAAA,I3BigLF,qFAEA,qFkDj6KA,wDlDg6KA,wDkDv3KQ,2BAAA,IACA,0BAAA,IlD43KR,oGAIA,oGAFA,oGAIA,oGkD56KA,uElDy6KA,uEAFA,uEAIA,uEkD73KU,0BAAA,IlDk4KV,mGAIA,mGAFA,mGAIA,mGkDt7KA,sElDm7KA,sEAFA,sEAIA,sEkDn4KU,2BAAA,IAlDV,0BlD07KA,qCACA,0BACA,qCkDj4KI,WAAA,IAAA,MAAA,KlDq4KJ,kDkDh8KA,kDA+DI,WAAA,EA/DJ,uBlDo8KA,yCkDj4KI,OAAA,ElD44KJ,+CANA,+CAQA,+CANA,+CAEA,+CkD78KA,+ClDg9KA,iEANA,iEAQA,iEANA,iEAEA,iEANA,iEkD93KU,YAAA,ElDm5KV,8CANA,8CAQA,8CANA,8CAEA,8CkD39KA,8ClD89KA,gEANA,gEAQA,gEANA,gEAEA,gEANA,gEkDx4KU,aAAA,ElDu5KV,+CAIA,+CkDz+KA,+ClDu+KA,+CADA,iEAIA,iEANA,iEAIA,iEkDj5KU,cAAA,EAvFV,8ClDi/KA,8CAFA,8CAIA,8CALA,gEAIA,gEAFA,gEAIA,gEkDp5KU,cAAA,EAhGV,yBAsGI,cAAA,EACA,OAAA,EAUJ,aACE,cAAA,KADF,oBAKI,cAAA,EACA,cAAA,IANJ,2BASM,WAAA,IATN,4BAcI,cAAA,ElD04KJ,wDkDx5KA,wDAkBM,WAAA,IAAA,MAAA,KAlBN,2BAuBI,WAAA,EAvBJ,uDAyBM,cAAA,IAAA,MAAA,KAON,eC5PE,aAAA,KAEA,8BACE,MAAA,KACA,iBAAA,QACA,aAAA,KAHF,0DAMI,iBAAA,KANJ,qCASI,MAAA,QACA,iBAAA,KAGJ,yDAEI,oBAAA,KD8ON,eC/PE,aAAA,QAEA,8BACE,MAAA,KACA,iBAAA,QACA,aAAA,QAHF,0DAMI,iBAAA,QANJ,qCASI,MAAA,QACA,iBAAA,KAGJ,yDAEI,oBAAA,QDiPN,eClQE,aAAA,QAEA,8BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,0DAMI,iBAAA,QANJ,qCASI,MAAA,QACA,iBAAA,QAGJ,yDAEI,oBAAA,QDoPN,YCrQE,aAAA,QAEA,2BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,uDAMI,iBAAA,QANJ,kCASI,MAAA,QACA,iBAAA,QAGJ,sDAEI,oBAAA,QDuPN,eCxQE,aAAA,QAEA,8BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,0DAMI,iBAAA,QANJ,qCASI,MAAA,QACA,iBAAA,QAGJ,yDAEI,oBAAA,QD0PN,cC3QE,aAAA,QAEA,6BACE,MAAA,QACA,iBAAA,QACA,aAAA,QAHF,yDAMI,iBAAA,QANJ,oCASI,MAAA,QACA,iBAAA,QAGJ,wDAEI,oBAAA,QChBN,kBACE,SAAA,SACA,QAAA,MACA,OAAA,EACA,QAAA,EACA,SAAA,OALF,yCpDivLA,wBADA,yBAEA,yBACA,wBoDvuLI,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,KACA,OAAA,KACA,OAAA,EAKJ,wBACE,eAAA,OAIF,uBACE,eAAA,IC3BF,MACE,WAAA,KACA,QAAA,KACA,cAAA,KACA,iBAAA,QACA,OAAA,IAAA,MAAA,QACA,cAAA,IjD0DA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBiDjEV,iBASI,aAAA,KACA,aAAA,gBAKJ,SACE,QAAA,KACA,cAAA,IAEF,SACE,QAAA,IACA,cAAA,ICpBF,OACE,MAAA,MACA,UAAA,KACA,YAAA,IACA,YAAA,EACA,MAAA,KACA,YAAA,EAAA,IAAA,EAAA,KjCTA,OAAA,kBACA,QAAA,GrBkyLF,asDvxLE,aAEE,MAAA,KACA,gBAAA,KACA,OAAA,QjChBF,OAAA,kBACA,QAAA,GiCuBA,aACE,QAAA,EACA,OAAA,QACA,WAAA,IACA,OAAA,EACA,mBAAA,KACA,gBAAA,KAAA,WAAA,KCxBJ,YACE,SAAA,OAIF,OACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,SAAA,OACA,2BAAA,MAIA,QAAA,EAGA,0BnDiHA,kBAAA,kBACI,cAAA,kBACC,aAAA,kBACG,UAAA,kBAkER,mBAAA,kBAAA,IAAA,SAEK,cAAA,aAAA,IAAA,SACG,WAAA,kBAAA,IAAA,SAAA,WAAA,UAAA,IAAA,SAAA,WAAA,UAAA,IAAA,QAAA,CAAA,kBAAA,IAAA,QAAA,CAAA,aAAA,IAAA,SmDrLR,wBnD6GA,kBAAA,eACI,cAAA,eACC,aAAA,eACG,UAAA,emD9GV,mBACE,WAAA,OACA,WAAA,KAIF,cACE,SAAA,SACA,MAAA,KACA,OAAA,KAIF,eACE,SAAA,SACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,KACA,OAAA,IAAA,MAAA,eACA,cAAA,InDcA,mBAAA,EAAA,IAAA,IAAA,eACQ,WAAA,EAAA,IAAA,IAAA,emDZR,QAAA,EAIF,gBACE,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,KACA,iBAAA,KAEA,qBlCpEA,OAAA,iBACA,QAAA,EkCoEA,mBlCrEA,OAAA,kBACA,QAAA,GkCyEF,cACE,QAAA,KACA,cAAA,IAAA,MAAA,QAIF,qBACE,WAAA,KAIF,aACE,OAAA,EACA,YAAA,WAKF,YACE,SAAA,SACA,QAAA,KAIF,cACE,QAAA,KACA,WAAA,MACA,WAAA,IAAA,MAAA,QAHF,wBAQI,cAAA,EACA,YAAA,IATJ,mCAaI,YAAA,KAbJ,oCAiBI,YAAA,EAKJ,yBACE,SAAA,SACA,IAAA,QACA,MAAA,KACA,OAAA,KACA,SAAA,OAIF,yBAEE,cACE,MAAA,MACA,OAAA,KAAA,KAEF,enDrEA,mBAAA,EAAA,IAAA,KAAA,eACQ,WAAA,EAAA,IAAA,KAAA,emDyER,UAAY,MAAA,OAGd,yBACE,UAAY,MAAA,OC9Id,SACE,SAAA,SACA,QAAA,KACA,QAAA,MCRA,YAAA,gBAAA,CAAA,SAAA,CAAA,KAAA,CAAA,WAEA,WAAA,OACA,YAAA,IACA,YAAA,WACA,WAAA,KACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,UAAA,OACA,YAAA,ODHA,UAAA,KnCTA,OAAA,iBACA,QAAA,EmCYA,YnCbA,OAAA,kBACA,QAAA,GmCaA,aACE,QAAA,IAAA,EACA,WAAA,KAEF,eACE,QAAA,EAAA,IACA,YAAA,IAEF,gBACE,QAAA,IAAA,EACA,WAAA,IAEF,cACE,QAAA,EAAA,IACA,YAAA,KAIF,4BACE,OAAA,EACA,KAAA,IACA,YAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEF,iCACE,MAAA,IACA,OAAA,EACA,cAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEF,kCACE,OAAA,EACA,KAAA,IACA,cAAA,KACA,aAAA,IAAA,IAAA,EACA,iBAAA,KAEF,8BACE,IAAA,IACA,KAAA,EACA,WAAA,KACA,aAAA,IAAA,IAAA,IAAA,EACA,mBAAA,KAEF,6BACE,IAAA,IACA,MAAA,EACA,WAAA,KACA,aAAA,IAAA,EAAA,IAAA,IACA,kBAAA,KAEF,+BACE,IAAA,EACA,KAAA,IACA,YAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEF,oCACE,IAAA,EACA,MAAA,IACA,WAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAEF,qCACE,IAAA,EACA,KAAA,IACA,WAAA,KACA,aAAA,EAAA,IAAA,IACA,oBAAA,KAKJ,eACE,UAAA,MACA,QAAA,IAAA,IACA,MAAA,KACA,WAAA,OACA,iBAAA,KACA,cAAA,IAIF,eACE,SAAA,SACA,MAAA,EACA,OAAA,EACA,aAAA,YACA,aAAA,MEzGF,SACE,SAAA,SACA,IAAA,EACA,KAAA,EACA,QAAA,KACA,QAAA,KACA,UAAA,MACA,QAAA,IDXA,YAAA,gBAAA,CAAA,SAAA,CAAA,KAAA,CAAA,WAEA,WAAA,OACA,YAAA,IACA,YAAA,WACA,WAAA,KACA,WAAA,KACA,WAAA,MACA,gBAAA,KACA,YAAA,KACA,eAAA,KACA,eAAA,OACA,WAAA,OACA,aAAA,OACA,UAAA,OACA,YAAA,OCAA,UAAA,KACA,iBAAA,KACA,gBAAA,YACA,OAAA,IAAA,MAAA,KACA,OAAA,IAAA,MAAA,eACA,cAAA,ItDiDA,mBAAA,EAAA,IAAA,KAAA,eACQ,WAAA,EAAA,IAAA,KAAA,esD9CR,aAAQ,WAAA,MACR,eAAU,YAAA,KACV,gBAAW,WAAA,KACX,cAAS,YAAA,MAvBX,gBA4BI,aAAA,KAEA,gB1DkjMJ,sB0DhjMM,SAAA,SACA,QAAA,MACA,MAAA,EACA,OAAA,EACA,aAAA,YACA,aAAA,MAGF,sBACE,QAAA,GACA,aAAA,KAIJ,oBACE,OAAA,MACA,KAAA,IACA,YAAA,MACA,iBAAA,KACA,iBAAA,gBACA,oBAAA,EACA,0BACE,OAAA,IACA,YAAA,MACA,QAAA,IACA,iBAAA,KACA,oBAAA,EAGJ,sBACE,IAAA,IACA,KAAA,MACA,WAAA,MACA,mBAAA,KACA,mBAAA,gBACA,kBAAA,EACA,4BACE,OAAA,MACA,KAAA,IACA,QAAA,IACA,mBAAA,KACA,kBAAA,EAGJ,uBACE,IAAA,MACA,KAAA,IACA,YAAA,MACA,iBAAA,EACA,oBAAA,KACA,oBAAA,gBACA,6BACE,IAAA,IACA,YAAA,MACA,QAAA,IACA,iBAAA,EACA,oBAAA,KAIJ,qBACE,IAAA,IACA,MAAA,MACA,WAAA,MACA,mBAAA,EACA,kBAAA,KACA,kBAAA,gBACA,2BACE,MAAA,IACA,OAAA,MACA,QAAA,IACA,mBAAA,EACA,kBAAA,KAKN,eACE,QAAA,IAAA,KACA,OAAA,EACA,UAAA,KACA,iBAAA,QACA,cAAA,IAAA,MAAA,QACA,cAAA,IAAA,IAAA,EAAA,EAGF,iBACE,QAAA,IAAA,KCpHF,UACE,SAAA,SAGF,gBACE,SAAA,SACA,MAAA,KACA,SAAA,OAHF,sBAMI,SAAA,SACA,QAAA,KvD6KF,mBAAA,IAAA,YAAA,KACK,cAAA,IAAA,YAAA,KACG,WAAA,IAAA,YAAA,KJs/LV,4B2D5qMA,0BAcM,YAAA,EAIF,8BAAA,uBAAA,sBvDuLF,mBAAA,kBAAA,IAAA,YAEK,cAAA,aAAA,IAAA,YACG,WAAA,kBAAA,IAAA,YAAA,WAAA,UAAA,IAAA,YAAA,WAAA,UAAA,IAAA,WAAA,CAAA,kBAAA,IAAA,WAAA,CAAA,aAAA,IAAA,YA7JR,4BAAA,OAEQ,oBAAA,OA+GR,oBAAA,OAEQ,YAAA,OJ0hMR,mC2DrqMI,2BvDmHJ,kBAAA,sBACQ,UAAA,sBuDjHF,KAAA,E3DwqMN,kC2DtqMI,2BvD8GJ,kBAAA,uBACQ,UAAA,uBuD5GF,KAAA,E3D0qMN,6B2DxqMI,gC3DuqMJ,iCI9jMA,kBAAA,mBACQ,UAAA,mBuDtGF,KAAA,GArCR,wB3DgtMA,sBACA,sB2DpqMI,QAAA,MA7CJ,wBAiDI,KAAA,EAjDJ,sB3DwtMA,sB2DlqMI,SAAA,SACA,IAAA,EACA,MAAA,KAxDJ,sBA4DI,KAAA,KA5DJ,sBA+DI,KAAA,MA/DJ,2B3DouMA,4B2DjqMI,KAAA,EAnEJ,6BAuEI,KAAA,MAvEJ,8BA0EI,KAAA,KAQJ,kBACE,SAAA,SACA,IAAA,EACA,OAAA,EACA,KAAA,EACA,MAAA,IACA,UAAA,KACA,MAAA,KACA,WAAA,OACA,YAAA,EAAA,IAAA,IAAA,eACA,iBAAA,ctCpGA,OAAA,kBACA,QAAA,GsCyGA,uBdrGE,iBAAA,sEACA,iBAAA,iEACA,iBAAA,uFAAA,iBAAA,kEACA,OAAA,+GACA,kBAAA,ScoGF,wBACE,MAAA,EACA,KAAA,Kd1GA,iBAAA,sEACA,iBAAA,iEACA,iBAAA,uFAAA,iBAAA,kEACA,OAAA,+GACA,kBAAA,S7C6wMJ,wB2DlqME,wBAEE,MAAA,KACA,gBAAA,KACA,QAAA,EtCxHF,OAAA,kBACA,QAAA,GrB8xMF,0CACA,2CAFA,6B2DpsMA,6BAuCI,SAAA,SACA,IAAA,IACA,QAAA,EACA,QAAA,aACA,WAAA,M3DmqMJ,0C2D9sMA,6BA+CI,KAAA,IACA,YAAA,M3DmqMJ,2C2DntMA,6BAoDI,MAAA,IACA,aAAA,M3DmqMJ,6B2DxtMA,6BAyDI,MAAA,KACA,OAAA,KACA,YAAA,MACA,YAAA,EAIA,oCACE,QAAA,QAIF,oCACE,QAAA,QAUN,qBACE,SAAA,SACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,MAAA,IACA,aAAA,EACA,YAAA,KACA,WAAA,OACA,WAAA,KATF,wBAYI,QAAA,aACA,MAAA,KACA,OAAA,KACA,OAAA,IACA,YAAA,OACA,OAAA,QAUA,iBAAA,OACA,iBAAA,cAEA,OAAA,IAAA,MAAA,KACA,cAAA,KA/BJ,6BAmCI,MAAA,KACA,OAAA,KACA,OAAA,EACA,iBAAA,KAOJ,kBACE,SAAA,SACA,MAAA,IACA,OAAA,KACA,KAAA,IACA,QAAA,GACA,YAAA,KACA,eAAA,KACA,MAAA,KACA,WAAA,OACA,YAAA,EAAA,IAAA,IAAA,eAEA,uBACE,YAAA,KAMJ,oCAGE,0C3D+nMA,2CAEA,6BADA,6B2D3nMI,MAAA,KACA,OAAA,KACA,WAAA,MACA,UAAA,KARJ,0C3DwoMA,6B2D5nMI,YAAA,MAZJ,2C3D4oMA,6B2D5nMI,aAAA,MAKJ,kBACE,MAAA,IACA,KAAA,IACA,eAAA,KAIF,qBACE,OAAA,M3D0oMJ,qCADA,sCADA,mBADA,oBAXA,gB4D73ME,iB5Dm4MF,uBADA,wBADA,iBADA,kBADA,wBADA,yBASA,mCADA,oCAqBA,oBADA,qBADA,oBADA,qBAXA,WADA,YAOA,uBADA,wBADA,qBADA,sBADA,cADA,eAOA,aADA,cAGA,kBADA,mBAjBA,WADA,Y4Dl4MI,QAAA,MACA,QAAA,I5Dm6MJ,qCADA,mB4Dh6ME,gB5D65MF,uBADA,iBADA,wBAIA,mCAUA,oBADA,oBANA,WAGA,uBADA,qBADA,cAGA,aACA,kBATA,W4D75MI,MAAA,K5BNJ,c6BVE,QAAA,MACA,aAAA,KACA,YAAA,K7BWF,YACE,MAAA,gBAEF,WACE,MAAA,eAQF,MACE,QAAA,eAEF,MACE,QAAA,gBAEF,WACE,WAAA,OAEF,W8BzBE,KAAA,CAAA,CAAA,EAAA,EACA,MAAA,YACA,YAAA,KACA,iBAAA,YACA,OAAA,E9B8BF,QACE,QAAA,eAOF,OACE,SAAA,M+BjCF,cACE,MAAA,a/D88MF,YADA,YADA,Y+Dt8MA,YClBE,QAAA,ehEs+MF,kBACA,mBACA,yBALA,kBACA,mBACA,yBALA,kBACA,mBACA,yB+Dz8MA,kB/Dq8MA,mBACA,yB+D17ME,QAAA,eAIA,yBAAA,YCjDA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhE4/MV,cgE3/MA,cACU,QAAA,sBDkDV,yBAAA,kBACE,QAAA,iBAIF,yBAAA,mBACE,QAAA,kBAIF,yBAAA,yBACE,QAAA,wBAKF,+CAAA,YCtEA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhE0hNV,cgEzhNA,cACU,QAAA,sBDuEV,+CAAA,kBACE,QAAA,iBAIF,+CAAA,mBACE,QAAA,kBAIF,+CAAA,yBACE,QAAA,wBAKF,gDAAA,YC3FA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhEwjNV,cgEvjNA,cACU,QAAA,sBD4FV,gDAAA,kBACE,QAAA,iBAIF,gDAAA,mBACE,QAAA,kBAIF,gDAAA,yBACE,QAAA,wBAKF,0BAAA,YChHA,QAAA,gBACA,iBAAU,QAAA,gBACV,cAAU,QAAA,oBhEslNV,cgErlNA,cACU,QAAA,sBDiHV,0BAAA,kBACE,QAAA,iBAIF,0BAAA,mBACE,QAAA,kBAIF,0BAAA,yBACE,QAAA,wBAKF,yBAAA,WC7HA,QAAA,gBDkIA,+CAAA,WClIA,QAAA,gBDuIA,gDAAA,WCvIA,QAAA,gBD4IA,0BAAA,WC5IA,QAAA,gBDuJF,eCvJE,QAAA,eD0JA,aAAA,eClKA,QAAA,gBACA,oBAAU,QAAA,gBACV,iBAAU,QAAA,oBhE2oNV,iBgE1oNA,iBACU,QAAA,sBDkKZ,qBACE,QAAA,eAEA,aAAA,qBACE,QAAA,iBAGJ,sBACE,QAAA,eAEA,aAAA,sBACE,QAAA,kBAGJ,4BACE,QAAA,eAEA,aAAA,4BACE,QAAA,wBAKF,aAAA,cCrLA,QAAA","sourcesContent":["/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: none;\n text-decoration: underline;\n text-decoration: underline dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important;\n text-shadow: none !important;\n background: transparent !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: \"Glyphicons Halflings\";\n src: url(\"../fonts/glyphicons-halflings-regular.eot\");\n src: url(\"../fonts/glyphicons-halflings-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/glyphicons-halflings-regular.woff2\") format(\"woff2\"), url(\"../fonts/glyphicons-halflings-regular.woff\") format(\"woff\"), url(\"../fonts/glyphicons-halflings-regular.ttf\") format(\"truetype\"), url(\"../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular\") format(\"svg\");\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: \"Glyphicons Halflings\";\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: 400;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: 700;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: \"\\2014 \\00A0\";\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: \"\";\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: \"\\00A0 \\2014\";\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n color: #333333;\n word-break: break-all;\n word-wrap: break-word;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n.row {\n margin-right: -15px;\n margin-left: -15px;\n}\n.row-no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n.row-no-gutters [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n.col-xs-1,\n.col-sm-1,\n.col-md-1,\n.col-lg-1,\n.col-xs-2,\n.col-sm-2,\n.col-md-2,\n.col-lg-2,\n.col-xs-3,\n.col-sm-3,\n.col-md-3,\n.col-lg-3,\n.col-xs-4,\n.col-sm-4,\n.col-md-4,\n.col-lg-4,\n.col-xs-5,\n.col-sm-5,\n.col-md-5,\n.col-lg-5,\n.col-xs-6,\n.col-sm-6,\n.col-md-6,\n.col-lg-6,\n.col-xs-7,\n.col-sm-7,\n.col-md-7,\n.col-lg-7,\n.col-xs-8,\n.col-sm-8,\n.col-md-8,\n.col-lg-8,\n.col-xs-9,\n.col-sm-9,\n.col-md-9,\n.col-lg-9,\n.col-xs-10,\n.col-sm-10,\n.col-md-10,\n.col-lg-10,\n.col-xs-11,\n.col-sm-11,\n.col-md-11,\n.col-lg-11,\n.col-xs-12,\n.col-sm-12,\n.col-md-12,\n.col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n.col-xs-1,\n.col-xs-2,\n.col-xs-3,\n.col-xs-4,\n.col-xs-5,\n.col-xs-6,\n.col-xs-7,\n.col-xs-8,\n.col-xs-9,\n.col-xs-10,\n.col-xs-11,\n.col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1,\n .col-sm-2,\n .col-sm-3,\n .col-sm-4,\n .col-sm-5,\n .col-sm-6,\n .col-sm-7,\n .col-sm-8,\n .col-sm-9,\n .col-sm-10,\n .col-sm-11,\n .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1,\n .col-md-2,\n .col-md-3,\n .col-md-4,\n .col-md-5,\n .col-md-6,\n .col-md-7,\n .col-md-8,\n .col-md-9,\n .col-md-10,\n .col-md-11,\n .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1,\n .col-lg-2,\n .col-lg-3,\n .col-lg-4,\n .col-lg-5,\n .col-lg-6,\n .col-lg-7,\n .col-lg-8,\n .col-lg-9,\n .col-lg-10,\n .col-lg-11,\n .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ntable col[class*=\"col-\"] {\n position: static;\n display: table-column;\n float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n display: table-cell;\n float: none;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n min-height: 0.01%;\n overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: 700;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n -webkit-appearance: none;\n appearance: none;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-top: 4px \\9;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n vertical-align: middle;\n cursor: pointer;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\n.form-control-static {\n min-height: 34px;\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-right: 0;\n padding-left: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n background-color: #f2dede;\n border-color: #a94442;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n padding-top: 7px;\n margin-top: 0;\n margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n padding-top: 7px;\n margin-bottom: 0;\n text-align: right;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n outline: 0;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n filter: alpha(opacity=65);\n opacity: 0.65;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n background-image: none;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n background-image: none;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n background-image: none;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n background-image: none;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n background-image: none;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n background-image: none;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n font-weight: 400;\n color: #337ab7;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n font-size: 14px;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: 400;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n color: #262626;\n text-decoration: none;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n background-color: #337ab7;\n outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n content: \"\";\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n right: 0;\n left: auto;\n }\n .navbar-right .dropdown-menu-left {\n right: auto;\n left: 0;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-right: 8px;\n padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-right: 12px;\n padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n display: table-cell;\n float: none;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-right: 0;\n padding-left: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n cursor: default;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n padding-right: 15px;\n padding-left: 15px;\n overflow-x: visible;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-right: 0;\n padding-left: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-brand {\n float: left;\n height: 50px;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n padding: 9px 10px;\n margin-right: 15px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n padding: 10px 15px;\n margin-right: -15px;\n margin-left: -15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n padding-top: 0;\n padding-bottom: 0;\n margin-right: 0;\n margin-left: 0;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n color: #fff;\n background-color: #080808;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n padding: 0 5px;\n color: #ccc;\n content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n margin-left: -1px;\n line-height: 1.42857143;\n color: #337ab7;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-top-left-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n cursor: default;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-top-left-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-top-right-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n text-align: center;\n list-style: none;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n}\n.label {\n display: inline;\n padding: 0.2em 0.6em 0.3em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n padding-right: 15px;\n padding-left: 15px;\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-right: 60px;\n padding-left: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-right: auto;\n margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n height: 20px;\n margin-bottom: 20px;\n overflow: hidden;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n padding-left: 0;\n margin-bottom: 20px;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #eeeeee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n color: #555;\n text-decoration: none;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-right: 15px;\n padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n margin-bottom: 0;\n border: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n filter: alpha(opacity=20);\n opacity: 0.2;\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.modal-backdrop.in {\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 12px;\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.tooltip.in {\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.tooltip.top {\n padding: 5px 0;\n margin-top: -3px;\n}\n.tooltip.right {\n padding: 0 5px;\n margin-left: 3px;\n}\n.tooltip.bottom {\n padding: 5px 0;\n margin-top: 3px;\n}\n.tooltip.left {\n padding: 0 5px;\n margin-left: -3px;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n right: 5px;\n bottom: 0;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 14px;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow:after {\n content: \"\";\n border-width: 10px;\n}\n.popover.top > .arrow {\n bottom: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n bottom: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-color: #fff;\n border-bottom-width: 0;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n border-left-width: 0;\n}\n.popover.right > .arrow:after {\n bottom: -10px;\n left: 1px;\n content: \" \";\n border-right-color: #fff;\n border-left-width: 0;\n}\n.popover.bottom > .arrow {\n top: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n.popover.bottom > .arrow:after {\n top: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n right: 1px;\n bottom: -10px;\n content: \" \";\n border-right-width: 0;\n border-left-color: #fff;\n}\n.popover-title {\n padding: 8px 14px;\n margin: 0;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner > .item {\n position: relative;\n display: none;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 15%;\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n background-color: rgba(0, 0, 0, 0);\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control.right {\n right: 0;\n left: auto;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n font-family: serif;\n line-height: 1;\n}\n.carousel-control .icon-prev:before {\n content: \"\\2039\";\n}\n.carousel-control .icon-next:before {\n content: \"\\203a\";\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n padding-left: 0;\n margin-left: -30%;\n text-align: center;\n list-style: none;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n border: 1px solid #fff;\n border-radius: 10px;\n}\n.carousel-indicators .active {\n width: 12px;\n height: 12px;\n margin: 0;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n right: 20%;\n left: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n display: table;\n content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-right: auto;\n margin-left: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","// stylelint-disable\n\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// 1. Remove the bottom border in Chrome 57- and Firefox 39-.\n// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n//\n\nabbr[title] {\n border-bottom: none; // 1\n text-decoration: underline; // 2\n text-decoration: underline dotted; // 2\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*!\n * Bootstrap v3.4.1 (https://getbootstrap.com/)\n * Copyright 2011-2019 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: none;\n text-decoration: underline;\n -webkit-text-decoration: underline dotted;\n -moz-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n -webkit-box-sizing: content-box;\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n -webkit-box-sizing: content-box;\n -moz-box-sizing: content-box;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important;\n text-shadow: none !important;\n background: transparent !important;\n -webkit-box-shadow: none !important;\n box-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: \"Glyphicons Halflings\";\n src: url(\"../fonts/glyphicons-halflings-regular.eot\");\n src: url(\"../fonts/glyphicons-halflings-regular.eot?#iefix\") format(\"embedded-opentype\"), url(\"../fonts/glyphicons-halflings-regular.woff2\") format(\"woff2\"), url(\"../fonts/glyphicons-halflings-regular.woff\") format(\"woff\"), url(\"../fonts/glyphicons-halflings-regular.ttf\") format(\"truetype\"), url(\"../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular\") format(\"svg\");\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: \"Glyphicons Halflings\";\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\002a\";\n}\n.glyphicon-plus:before {\n content: \"\\002b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #fff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: 400;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n padding: 0.2em;\n background-color: #fcf8e3;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: 700;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: \"\\2014 \\00A0\";\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: \"\";\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: \"\\00A0 \\2014\";\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #fff;\n background-color: #333;\n border-radius: 3px;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n color: #333333;\n word-break: break-all;\n word-wrap: break-word;\n background-color: #f5f5f5;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n padding-right: 15px;\n padding-left: 15px;\n margin-right: auto;\n margin-left: auto;\n}\n.row {\n margin-right: -15px;\n margin-left: -15px;\n}\n.row-no-gutters {\n margin-right: 0;\n margin-left: 0;\n}\n.row-no-gutters [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n}\n.col-xs-1,\n.col-sm-1,\n.col-md-1,\n.col-lg-1,\n.col-xs-2,\n.col-sm-2,\n.col-md-2,\n.col-lg-2,\n.col-xs-3,\n.col-sm-3,\n.col-md-3,\n.col-lg-3,\n.col-xs-4,\n.col-sm-4,\n.col-md-4,\n.col-lg-4,\n.col-xs-5,\n.col-sm-5,\n.col-md-5,\n.col-lg-5,\n.col-xs-6,\n.col-sm-6,\n.col-md-6,\n.col-lg-6,\n.col-xs-7,\n.col-sm-7,\n.col-md-7,\n.col-lg-7,\n.col-xs-8,\n.col-sm-8,\n.col-md-8,\n.col-lg-8,\n.col-xs-9,\n.col-sm-9,\n.col-md-9,\n.col-lg-9,\n.col-xs-10,\n.col-sm-10,\n.col-md-10,\n.col-lg-10,\n.col-xs-11,\n.col-sm-11,\n.col-md-11,\n.col-lg-11,\n.col-xs-12,\n.col-sm-12,\n.col-md-12,\n.col-lg-12 {\n position: relative;\n min-height: 1px;\n padding-right: 15px;\n padding-left: 15px;\n}\n.col-xs-1,\n.col-xs-2,\n.col-xs-3,\n.col-xs-4,\n.col-xs-5,\n.col-xs-6,\n.col-xs-7,\n.col-xs-8,\n.col-xs-9,\n.col-xs-10,\n.col-xs-11,\n.col-xs-12 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .col-sm-1,\n .col-sm-2,\n .col-sm-3,\n .col-sm-4,\n .col-sm-5,\n .col-sm-6,\n .col-sm-7,\n .col-sm-8,\n .col-sm-9,\n .col-sm-10,\n .col-sm-11,\n .col-sm-12 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .col-md-1,\n .col-md-2,\n .col-md-3,\n .col-md-4,\n .col-md-5,\n .col-md-6,\n .col-md-7,\n .col-md-8,\n .col-md-9,\n .col-md-10,\n .col-md-11,\n .col-md-12 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .col-lg-1,\n .col-lg-2,\n .col-lg-3,\n .col-lg-4,\n .col-lg-5,\n .col-lg-6,\n .col-lg-7,\n .col-lg-8,\n .col-lg-9,\n .col-lg-10,\n .col-lg-11,\n .col-lg-12 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ntable col[class*=\"col-\"] {\n position: static;\n display: table-column;\n float: none;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n display: table-cell;\n float: none;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #ddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #ddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #ddd;\n}\n.table .table {\n background-color: #fff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #ddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n min-height: 0.01%;\n overflow-x: auto;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #ddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: 700;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #fff;\n background-image: none;\n border: 1px solid #ccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999;\n}\n.form-control::-ms-expand {\n background-color: transparent;\n border: 0;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-top: 4px \\9;\n margin-left: -20px;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: 400;\n vertical-align: middle;\n cursor: pointer;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\n.form-control-static {\n min-height: 34px;\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-right: 0;\n padding-left: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #3c763d;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #8a6d3b;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n background-color: #f2dede;\n border-color: #a94442;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n padding-top: 7px;\n margin-top: 0;\n margin-bottom: 0;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n padding-top: 7px;\n margin-bottom: 0;\n text-align: right;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 11px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n -ms-touch-action: manipulation;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n outline: 0;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n filter: alpha(opacity=65);\n opacity: 0.65;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333;\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333;\n background-color: #e6e6e6;\n background-image: none;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus {\n background-color: #fff;\n border-color: #ccc;\n}\n.btn-default .badge {\n color: #fff;\n background-color: #333;\n}\n.btn-primary {\n color: #fff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #fff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #fff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #fff;\n background-color: #286090;\n background-image: none;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #fff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.btn-success {\n color: #fff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #fff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #fff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #fff;\n background-color: #449d44;\n background-image: none;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #fff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #fff;\n}\n.btn-info {\n color: #fff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #fff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #fff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #fff;\n background-color: #31b0d5;\n background-image: none;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #fff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #fff;\n}\n.btn-warning {\n color: #fff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #fff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #fff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #fff;\n background-color: #ec971f;\n background-image: none;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #fff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #fff;\n}\n.btn-danger {\n color: #fff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #fff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #fff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #fff;\n background-color: #c9302c;\n background-image: none;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #fff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #fff;\n}\n.btn-link {\n font-weight: 400;\n color: #337ab7;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n -o-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n -o-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n -o-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n font-size: 14px;\n text-align: left;\n list-style: none;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: 400;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n color: #262626;\n text-decoration: none;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #fff;\n text-decoration: none;\n background-color: #337ab7;\n outline: 0;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu-left {\n right: auto;\n left: 0;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n content: \"\";\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n right: 0;\n left: auto;\n }\n .navbar-right .dropdown-menu-left {\n right: auto;\n left: 0;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-right: 8px;\n padding-left: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-right: 12px;\n padding-left: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n display: table-cell;\n float: none;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-right: 0;\n padding-left: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group .form-control:focus {\n z-index: 3;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: 400;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #ccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n padding-left: 0;\n margin-bottom: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n cursor: not-allowed;\n background-color: transparent;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #ddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #ddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n cursor: default;\n background-color: #fff;\n border: 1px solid #ddd;\n border-bottom-color: transparent;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #fff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n margin-bottom: 5px;\n text-align: center;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #ddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #ddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #fff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n padding-right: 15px;\n padding-left: 15px;\n overflow-x: visible;\n border-top: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-right: 0;\n padding-left: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-brand {\n float: left;\n height: 50px;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n padding: 9px 10px;\n margin-right: 15px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n padding: 10px 15px;\n margin-right: -15px;\n margin-left: -15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n padding-top: 0;\n padding-bottom: 0;\n margin-right: 0;\n margin-left: 0;\n border: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-right: 15px;\n margin-left: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n color: #555;\n background-color: #e7e7e7;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #ccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-toggle {\n border-color: #ddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #ddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-link {\n color: #777;\n}\n.navbar-default .navbar-link:hover {\n color: #333;\n}\n.navbar-default .btn-link {\n color: #777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #ccc;\n}\n.navbar-inverse {\n background-color: #222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #fff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #fff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n color: #fff;\n background-color: #080808;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #fff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #fff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #fff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #fff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n padding: 0 5px;\n color: #ccc;\n content: \"/\\00a0\";\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n margin-left: -1px;\n line-height: 1.42857143;\n color: #337ab7;\n text-decoration: none;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 2;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #ddd;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-top-left-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 4px;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 3;\n color: #fff;\n cursor: default;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n border-color: #ddd;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-top-left-radius: 6px;\n border-bottom-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-top-right-radius: 6px;\n border-bottom-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-top-left-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-top-right-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n text-align: center;\n list-style: none;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n cursor: not-allowed;\n background-color: #fff;\n}\n.label {\n display: inline;\n padding: 0.2em 0.6em 0.3em;\n font-size: 75%;\n font-weight: 700;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: 0.25em;\n}\na.label:hover,\na.label:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n line-height: 1;\n color: #fff;\n text-align: center;\n white-space: nowrap;\n vertical-align: middle;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #fff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n padding-right: 15px;\n padding-left: 15px;\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-right: 60px;\n padding-left: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #fff;\n border: 1px solid #ddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-right: auto;\n margin-left: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@-o-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n height: 20px;\n margin-bottom: 20px;\n overflow: hidden;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #fff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n -webkit-background-size: 40px 40px;\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n overflow: hidden;\n zoom: 1;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n padding-left: 0;\n margin-bottom: 20px;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #fff;\n border: 1px solid #ddd;\n}\n.list-group-item:first-child {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n color: #777777;\n cursor: not-allowed;\n background-color: #eeeeee;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n color: #555;\n text-decoration: none;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #fff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #ddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-right: 15px;\n padding-left: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #ddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n margin-bottom: 0;\n border: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #ddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #ddd;\n}\n.panel-default {\n border-color: #ddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #ddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #fff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #fff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000;\n text-shadow: 0 1px 0 #fff;\n filter: alpha(opacity=20);\n opacity: 0.2;\n}\n.close:hover,\n.close:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n display: none;\n overflow: hidden;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: -webkit-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out, -o-transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000;\n}\n.modal-backdrop.fade {\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.modal-backdrop.in {\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-bottom: 0;\n margin-left: 5px;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 12px;\n filter: alpha(opacity=0);\n opacity: 0;\n}\n.tooltip.in {\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.tooltip.top {\n padding: 5px 0;\n margin-top: -3px;\n}\n.tooltip.right {\n padding: 0 5px;\n margin-left: 3px;\n}\n.tooltip.bottom {\n padding: 5px 0;\n margin-top: 3px;\n}\n.tooltip.left {\n padding: 0 5px;\n margin-left: -3px;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-left .tooltip-arrow {\n right: 5px;\n bottom: 0;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #fff;\n text-align: center;\n background-color: #000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: 400;\n line-height: 1.42857143;\n line-break: auto;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n white-space: normal;\n font-size: 14px;\n background-color: #fff;\n background-clip: padding-box;\n border: 1px solid #ccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow:after {\n content: \"\";\n border-width: 10px;\n}\n.popover.top > .arrow {\n bottom: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n border-bottom-width: 0;\n}\n.popover.top > .arrow:after {\n bottom: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-color: #fff;\n border-bottom-width: 0;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n border-left-width: 0;\n}\n.popover.right > .arrow:after {\n bottom: -10px;\n left: 1px;\n content: \" \";\n border-right-color: #fff;\n border-left-width: 0;\n}\n.popover.bottom > .arrow {\n top: -11px;\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n}\n.popover.bottom > .arrow:after {\n top: 1px;\n margin-left: -10px;\n content: \" \";\n border-top-width: 0;\n border-bottom-color: #fff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n right: 1px;\n bottom: -10px;\n content: \" \";\n border-right-width: 0;\n border-left-color: #fff;\n}\n.popover-title {\n padding: 8px 14px;\n margin: 0;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n width: 100%;\n overflow: hidden;\n}\n.carousel-inner > .item {\n position: relative;\n display: none;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: -webkit-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out, -webkit-transform 0.6s ease-in-out, -o-transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 15%;\n font-size: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n background-color: rgba(0, 0, 0, 0);\n filter: alpha(opacity=50);\n opacity: 0.5;\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control.right {\n right: 0;\n left: auto;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n background-repeat: repeat-x;\n}\n.carousel-control:hover,\n.carousel-control:focus {\n color: #fff;\n text-decoration: none;\n outline: 0;\n filter: alpha(opacity=90);\n opacity: 0.9;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n z-index: 5;\n display: inline-block;\n margin-top: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n font-family: serif;\n line-height: 1;\n}\n.carousel-control .icon-prev:before {\n content: \"\\2039\";\n}\n.carousel-control .icon-next:before {\n content: \"\\203a\";\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n padding-left: 0;\n margin-left: -30%;\n text-align: center;\n list-style: none;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n border: 1px solid #fff;\n border-radius: 10px;\n}\n.carousel-indicators .active {\n width: 12px;\n height: 12px;\n margin: 0;\n background-color: #fff;\n}\n.carousel-caption {\n position: absolute;\n right: 15%;\n bottom: 20px;\n left: 15%;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #fff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -10px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -10px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -10px;\n }\n .carousel-caption {\n right: 20%;\n left: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-header:before,\n.modal-header:after,\n.modal-footer:before,\n.modal-footer:after {\n display: table;\n content: \" \";\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-header:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-right: auto;\n margin-left: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","// stylelint-disable declaration-no-important, selector-no-qualifying-type\n\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n color: #000 !important; // Black prints faster: h5bp.com/s\n text-shadow: none !important;\n background: transparent !important;\n box-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n}\n","// stylelint-disable value-list-comma-newline-after, value-list-comma-space-after, indentation, declaration-colon-newline-after, font-family-no-missing-generic-family-keyword\n\n//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// Star\n\n// Import the fonts\n@font-face {\n font-family: \"Glyphicons Halflings\";\n src: url(\"@{icon-font-path}@{icon-font-name}.eot\");\n src: url(\"@{icon-font-path}@{icon-font-name}.eot?#iefix\") format(\"embedded-opentype\"),\n url(\"@{icon-font-path}@{icon-font-name}.woff2\") format(\"woff2\"),\n url(\"@{icon-font-path}@{icon-font-name}.woff\") format(\"woff\"),\n url(\"@{icon-font-path}@{icon-font-name}.ttf\") format(\"truetype\"),\n url(\"@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}\") format(\"svg\");\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: \"Glyphicons Halflings\";\n font-style: normal;\n font-weight: 400;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\002a\"; } }\n.glyphicon-plus { &:before { content: \"\\002b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// https://getbootstrap.com/docs/3.4/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: https://a11yproject.com/posts/how-to-hide-content\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// stylelint-disable indentation, property-no-vendor-prefix, selector-no-vendor-prefix\n\n// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n word-wrap: break-word;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // WebKit-specific. Other browsers will keep their default outline style.\n // (Initially tried to also force default via `outline: initial`,\n // but that seems to erroneously remove the outline in Firefox altogether.)\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// stylelint-disable media-feature-name-no-vendor-prefix, media-feature-parentheses-space-inside, media-feature-name-no-unknown, indentation, at-rule-name-space-after\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","// stylelint-disable selector-list-comma-newline-after, selector-no-qualifying-type\n\n//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: 400;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n padding: .2em;\n background-color: @state-warning-bg;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-right: 5px;\n padding-left: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: 700;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @dl-horizontal-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n}\n\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: \"\\2014 \\00A0\"; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n text-align: right;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: \"\"; }\n &:after {\n content: \"\\00A0 \\2014\"; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: 700;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n color: @pre-color;\n word-break: break-all;\n word-wrap: break-word;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n.row-no-gutters {\n margin-right: 0;\n margin-left: 0;\n\n [class*=\"col-\"] {\n padding-right: 0;\n padding-left: 0;\n }\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n padding-right: ceil((@gutter / 2));\n padding-left: floor((@gutter / 2));\n margin-right: auto;\n margin-left: auto;\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-right: floor((@gutter / -2));\n margin-left: ceil((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-right: (@gutter / 2);\n padding-left: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-right: floor((@grid-gutter-width / 2));\n padding-left: ceil((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","// stylelint-disable selector-max-type, selector-max-compound-selectors, selector-no-qualifying-type\n\n//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n\n // Table cell sizing\n //\n // Reset default table behavior\n\n col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n display: table-column;\n float: none;\n }\n\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n display: table-cell;\n float: none;\n }\n }\n}\n\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\n\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n min-height: .01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n overflow-x: auto;\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * .75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","// stylelint-disable selector-no-qualifying-type, property-no-vendor-prefix, media-feature-name-no-vendor-prefix\n\n//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n padding: 0;\n margin: 0;\n border: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: 700;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\ninput[type=\"search\"] {\n // Override content-box in Normalize (* isn't specific enough)\n .box-sizing(border-box);\n\n // Search inputs in iOS\n //\n // This overrides the extra rounded corners on search inputs in iOS so that our\n // `.form-control` class can properly style them. Note that this cannot simply\n // be added to `.form-control` as it's not specific enough. For details, see\n // https://github.com/twbs/bootstrap/issues/11586.\n -webkit-appearance: none;\n appearance: none;\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n\n // Apply same disabled cursor tweak as for inputs\n // Some special care is needed because