3 Commits

Author SHA1 Message Date
RoaringFlame
9439ba1bdb Pre Merge pull request !319 from RoaringFlame/k8s-deployment 2025-03-11 04:52:43 +00:00
java-ch
660162038a 更新k8s配置 2024-01-11 15:41:28 +08:00
Heng Chen
50b538ec80 增加k8s部署文件 2023-04-06 00:00:28 +08:00
188 changed files with 4378 additions and 2748 deletions

View File

@@ -1,11 +1,11 @@
<p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png">
</p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.6</h1>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.5</h1>
<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
<p align="center">
<a href="https://gitee.com/y_project/RuoYi-Cloud/stargazers"><img src="https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.6-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.5-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p>

54
deployment/README.md Normal file
View File

@@ -0,0 +1,54 @@
# Kubernates 部署Ruoyi-Cloud项目
本部署所用到的k8s配置均为简易版仅作为初步入门学习使用有不合理的地方还请见谅。
### 后期考虑功能:
* HPA自动扩缩容
* MySQL主从、Redis集群、服务集群
* ELK日志收集
## 容器分布
~~~
namespace
├── redis
│ └── redis // StatefulSet
├── kube-ruoyi
│ └── ruoyi-mysql // Deployment
│ └── ruoyi-nacos
│ └── ruoyi-nginx
│ └── ruoyi-sentinel
│ └── ruoyi-gateway
│ └── ruoyi-auth
│ └── ruoyi-system
│ └── ruoyi-gen
│ └── ruoyi-job
│ └── ruoyi-file
│ └── ruoyi-monitor
│ └── elasticsearch
│ └── skywalking
│ └── skywalking-ui
├── minio
│ └── minio
├── monitor-sa
│ └── node-exporter
│ └── prometheus-server
│ └── monitoring-grafana
~~~
## 部署顺序及要点
1. Redis
2. MySQL手动Dockerfile打包镜像初始化准备好的数据脚本。使用了Secret加密密码等配置。
3. Nacos, 配置好MODE=standalone使用configMap设置数据库。
4. Sentinel
5. Gateway本服务需要用Dockerfile打包镜像否则会报错。其他RuoYi服务可以直接使用spring-boot的image命令一键打包生成镜像[每个服务都有使用额外的SpringBoot配置文件bootstrap-k8s.yml加入到服务中同时在原配置文件中把active换成${SPRING_PROFILES_ACTIVE:dev}后再打包以读取deployment的env变量。启动服务前记得提前在nacos中克隆新增服务配置以把dev改成k8sdeployment中启动的环境是SPRING_PROFILES_ACTIVE=k8s修改好Redis地址redis.redis、MySQL地址(ruoyi-mysql)、Sentinel地址(ruoyi-sentinel)]
6. Nginx部署之前先打包好前端静态文件使用本地磁盘方式挂载到容器 (注我使用的是Window的DockerDesktop启动的K8s挂载磁盘路径必须带/run/desktop/mnt/host)修改好nginx配置ruoyi-gateway就可以启动启动后输入localhost:30080就可以访问前端项目
7. Auth
8. System配置好后就可以登录了
9. Gen
10. Job
11. File改成minio服务之后需要修改静态文件中读取文件的端口地址
12. Monitor需要修改前端静态文件中的Monitor端口地址
13. Minio挂载本地文件。修改ruoyi-file服务中@Primary注释改到MinioServer上以使用Minio服务记得修改nacos配置
14. Elasticsearch部署文件一并放入到了skywalking文件夹中
15. skywalking需要在Java服务中使用agent进行跟踪自制agent镜像然后使用initContainers方式挂载到同一个容器模板放到了agent-in-server文件
16. skywalking-ui

View File

@@ -0,0 +1,54 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: minio
name: minio
namespace: minio
spec:
replicas: 1
selector:
matchLabels:
app: minio
template:
metadata:
labels:
app: minio
spec:
containers:
- name: minio
image: minio/minio
imagePullPolicy: Always
ports:
- containerPort: 9000
name: tcp
- containerPort: 9090
protocol: TCP
name: console
command:
- /bin/sh
- -c
- minio server /data --console-address ":9090"
env:
- name: MINIO_ACCESS_KEY
value: minioadmin
- name: MINIO_SECRET_KEY
value: minioadmin
readinessProbe:
failureThreshold: 3
httpGet:
path: /minio/health/ready
port: 9000
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- mountPath: /data
name: minio-data
volumes:
- name: minio-data
hostPath:
path: /run/desktop/mnt/host/c/k8sVolume/minio/data
type: Directory

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: minio

View File

@@ -0,0 +1,20 @@
apiVersion: v1
kind: Service
metadata:
name: minio
namespace: minio
labels:
app: minio
spec:
type: NodePort
publishNotReadyAddresses: true
ports:
- port: 9000
name: tcp
targetPort: 9000
- port: 9090
name: console
targetPort: 9090
nodePort: 30090
selector:
app: minio

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: monitor-sa

View File

@@ -0,0 +1,63 @@
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitor-sa
labels:
name: node-exporter
spec:
selector:
matchLabels:
name: node-exporter
template:
metadata:
labels:
name: node-exporter
spec:
hostPID: true
hostIPC: true
hostNetwork: true # 共享宿主机网络和进程
containers:
- name: node-exporter
image: prom/node-exporter:v0.16.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9100 # 容器暴露端口为9100
resources:
requests:
cpu: 0.15
securityContext:
privileged: true # 开启特权模式
args:
- --path.procfs
- /host/proc
- --path.sysfs
- /host/sys
- --collector.filesystem.ignored-mount-points
- '"^/(sys|proc|dev|host|etc)($|/)"'
volumeMounts: # 挂载宿主机目录以收集宿主机信息
- name: dev
mountPath: /host/dev
- name: proc
mountPath: /host/proc
- name: sys
mountPath: /host/sys
- name: rootfs
mountPath: /rootfs
tolerations: # 定义容忍度使其可调度到默认有污点的master
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "NoSchedule"
volumes: # 定义存储卷
- name: proc
hostPath:
path: /proc
- name: dev
hostPath:
path: /dev
- name: sys
hostPath:
path: /sys
- name: rootfs
hostPath:
path: /

View File

@@ -0,0 +1,169 @@
apiVersion: v1
kind: ConfigMap #
metadata:
name: prometheus-config
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: EnsureExists
data:
prometheus.yml: |
rule_files:
- /etc/config/rules/*.rules
scrape_configs:
- job_name: prometheus
static_configs:
- targets:
- localhost:9090
- job_name: kubernetes-nodes
scrape_interval: 30s
static_configs:
- targets:
- 192.168.73.135:9100
- 192.168.73.138:9100
- 192.168.73.139:9100
- 192.168.73.140:9100
- job_name: kubernetes-apiservers
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- action: keep
regex: default;kubernetes;https
source_labels:
- __meta_kubernetes_namespace
- __meta_kubernetes_service_name
- __meta_kubernetes_endpoint_port_name
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
- job_name: kubernetes-nodes-kubelet
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
- job_name: kubernetes-nodes-cadvisor
kubernetes_sd_configs:
- role: node
relabel_configs:
- action: labelmap
regex: __meta_kubernetes_node_label_(.+)
- target_label: __metrics_path__
replacement: /metrics/cadvisor
scheme: https
tls_config:
ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
insecure_skip_verify: true
bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
- job_name: kubernetes-service-endpoints
kubernetes_sd_configs:
- role: endpoints
relabel_configs:
- action: keep
regex: true
source_labels:
- __meta_kubernetes_service_annotation_prometheus_io_scrape
- action: replace
regex: (https?)
source_labels:
- __meta_kubernetes_service_annotation_prometheus_io_scheme
target_label: __scheme__
- action: replace
regex: (.+)
source_labels:
- __meta_kubernetes_service_annotation_prometheus_io_path
target_label: __metrics_path__
- action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
source_labels:
- __address__
- __meta_kubernetes_service_annotation_prometheus_io_port
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: kubernetes_namespace
- action: replace
source_labels:
- __meta_kubernetes_service_name
target_label: kubernetes_name
- job_name: kubernetes-services
kubernetes_sd_configs:
- role: service
metrics_path: /probe
params:
module:
- http_2xx
relabel_configs:
- action: keep
regex: true
source_labels:
- __meta_kubernetes_service_annotation_prometheus_io_probe
- source_labels:
- __address__
target_label: __param_target
- replacement: blackbox
target_label: __address__
- source_labels:
- __param_target
target_label: instance
- action: labelmap
regex: __meta_kubernetes_service_label_(.+)
- source_labels:
- __meta_kubernetes_namespace
target_label: kubernetes_namespace
- source_labels:
- __meta_kubernetes_service_name
target_label: kubernetes_name
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- action: keep
regex: true
source_labels:
- __meta_kubernetes_pod_annotation_prometheus_io_scrape
- action: replace
regex: (.+)
source_labels:
- __meta_kubernetes_pod_annotation_prometheus_io_path
target_label: __metrics_path__
- action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
source_labels:
- __address__
- __meta_kubernetes_pod_annotation_prometheus_io_port
target_label: __address__
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- action: replace
source_labels:
- __meta_kubernetes_namespace
target_label: kubernetes_namespace
- action: replace
source_labels:
- __meta_kubernetes_pod_name
target_label: kubernetes_pod_name
alerting:
alertmanagers:
- static_configs:
- targets: ["alertmanager:80"]

View File

@@ -0,0 +1 @@
存放sql目录下的所有脚本用于docker自动执行。

View File

@@ -0,0 +1,5 @@
# 基础镜像
FROM mysql:5.7
# 执行sql脚本
ADD ./db/*.sql /docker-entrypoint-initdb.d/

View File

@@ -0,0 +1,47 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruoyi-mysql #指定deployment的名字
namespace: kube-ruoyi
labels:
app: ruoyi-mysql-local
spec: #规约
replicas: 1 #pod的副本数量就是希望创建多少个pod的副本.可p选字段。它的默认值是1。
selector: #selector 字段定义 Deployment 如何查找要管理的 Pods。必须匹配 .spec.template.metadata.labels否则请求会被 API 拒绝。
matchLabels:
app: ruoyi-mysql-local
template: #Deployment Pod 模板;它和 Pod 的语法规则完全相同。 只是这里它是嵌套的,因此不需要 apiVersion 或 kind。
metadata:
labels:
app: ruoyi-mysql-local
spec: #pod模板规约
containers: #容器
- name: ruoyi-mysql #容器的名称
image: ruoyi/mysql:5.7 #容器使用的镜像
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-local-data #pv的name
mountPath: /var/lib/mysql #MySQL容器的数据都是存在这个目录的要对这个目录做数据持久化
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom: # Read environment variables from kubernetes secrets
secretKeyRef:
name: ruoyi-mysql-secret
key: mysql-root-pass
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: ruoyi-mysql-secret
key: mysql-user
- name: MYSQL_PASSWORD
valueFrom:
secretKeyRef:
name: ruoyi-mysql-secret
key: mysql-password
volumes:
- name: mysql-local-data #pv的name
hostPath:
path: /run/desktop/mnt/host/c/k8sVolume/mysql/data
type: Directory
restartPolicy: Always #Deployment 中的 Pod 模板必须指定适当的标签和适当的重新启动策略。只有 .spec.template.spec.restartPolicy 等于 Always 才是被允许的,这也是在没有指定时的默认设置

View File

@@ -0,0 +1,29 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
namespace: kube-ruoyi
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain # 手动删除
storageClassName: hostpath #表明这个pv所属的storageClass
hostPath:
path: /mnt/data #节点上卷的完整路径。必须是存在的路径不然容器无法创建deployment会报错可以是目录或块设备(磁盘、分区…)。
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc-local
namespace: kube-ruoyi
spec:
accessModes: #访问模式 申领在请求具有特定访问模式的存储时,使用与卷相同的访问模式约定。
- ReadWriteMany
volumeMode: Filesystem #卷模式
resources:
requests:
storage: 1Gi
storageClassName: hostpath # 此处须显式设置空字符串或指定值,否则会被设置为默认的 StorageClass

View File

@@ -0,0 +1,10 @@
apiVersion: v1
kind: Secret
metadata:
name: ruoyi-mysql-secret
namespace: kube-ruoyi
type: Opaque #base-64加密
data:
mysql-root-pass: cGFzc3dvcmQ=
mysql-user: YWRtaW4=
mysql-password: MTIzNDU2

View File

@@ -0,0 +1,12 @@
apiVersion: v1
kind: Service
metadata:
name: ruoyi-mysql
namespace: kube-ruoyi
spec:
ports:
- port: 3306
nodePort: 30060
selector:
app: ruoyi-mysql-local # 该 Service 会将所有具有标签 app: mysql-labels-app暴露到一个抽象的 Service 端口上targetPort容器接收流量的端口port可任意取值的抽象的 Service 端口,其他 Pod 通过该端口访问 Service
type: NodePort

View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: ruoyi-nacos-config
namespace: kube-ruoyi
data:
application.properties: |
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://ruoyi-mysql:3306/ry-config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user=root
db.password=password
nacos.naming.empty-service.auto-clean=true
nacos.naming.empty-service.clean.initial-delay-ms=50000
nacos.naming.empty-service.clean.period-time-ms=30000
management.endpoints.web.exposure.include=*
management.metrics.export.elastic.enabled=false
management.metrics.export.influx.enabled=false
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D %{User-Agent}i %{Request-Source}i
server.tomcat.basedir=/home/ruoyi/nacos/tomcat/logs
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
nacos.core.auth.system.type=nacos
nacos.core.auth.enabled=false
nacos.core.auth.plugin.nacos.token.expire.seconds=18000
nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789
nacos.core.auth.caching.enabled=true
nacos.core.auth.enable.userAgentAuthWhite=false
nacos.core.auth.server.identity.key=serverIdentity
nacos.core.auth.server.identity.value=security
nacos.istio.mcp.server.enabled=false

View File

@@ -0,0 +1,37 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruoyi-nacos
namespace: kube-ruoyi
spec:
replicas: 1
selector:
matchLabels:
app: ruoyi-nacos
template:
metadata:
labels:
app: ruoyi-nacos
spec:
containers:
- name: ruoyi-nacos
image: nacos/nacos-server
imagePullPolicy: Always
ports:
- containerPort: 8848
name: client
- containerPort: 9848
name: client-rpc
- containerPort: 9849
name: raft-rpc
env:
- name: MODE
value: standalone
volumeMounts:
- mountPath: /home/nacos/conf/application.properties
name: nacos-conf
subPath: application.properties
volumes:
- name: nacos-conf
configMap:
name: ruoyi-nacos-config

View File

@@ -0,0 +1,23 @@
apiVersion: v1
kind: Service
metadata:
name: ruoyi-nacos
namespace: kube-ruoyi
labels:
app: ruoyi-nacos
spec:
type: NodePort
publishNotReadyAddresses: true
ports:
- port: 8848
name: server
targetPort: 8848
nodePort: 30848
- port: 9848
name: client-rpc
targetPort: 9848
- port: 9849
name: raft-rpc
targetPort: 9849
selector:
app: ruoyi-nacos

View File

@@ -0,0 +1,37 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: ruoyi-nginx-config
namespace: kube-ruoyi
data:
nginx.conf: |
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root /home/ruoyi/projects/ruoyi-ui;
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://ruoyi-gateway:8080/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}

View File

@@ -0,0 +1,53 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruoyi-nginx
namespace: kube-ruoyi
spec:
replicas: 1
selector:
matchLabels:
app: ruoyi-nginx
template:
metadata:
labels:
app: ruoyi-nginx
spec:
containers:
- name: ruoyi-nginx
image: nginx
imagePullPolicy: Always
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/nginx.conf
name: nginx-conf
subPath: nginx.conf
- mountPath: /home/ruoyi/projects/ruoyi-ui
name: local-path #/usr/share/nginx/html 挂载到volumes中server+path
volumes:
- name: nginx-conf
configMap:
name: ruoyi-nginx-config
- name: local-path
hostPath:
path: /run/desktop/mnt/host/c/k8sVolume/dist
type: Directory
---
apiVersion: v1
kind: Service
metadata:
name: ruoyi-nginx
namespace: kube-ruoyi
labels:
name: ruoyi-nginx
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
selector:
app: ruoyi-nginx

View File

@@ -0,0 +1,58 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: redis
data:
redis.conf: |-
maxmemory 1000mb
maxmemory-policy allkeys-lru
protected-mode no
tcp-backlog 511
daemonize no
supervised no
dir /data
pidfile /data/redis_6379.pid
port 6379
loglevel notice
logfile ""
databases 16
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
replica-serve-stale-data yes
replica-read-only no
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
replica-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
replica-lazy-flush no
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble yes
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
set-max-intset-entries 512
hll-sparse-max-bytes 3000
stream-node-max-bytes 4096
stream-node-max-entries 100
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
dynamic-hz yes
aof-rewrite-incremental-fsync yes
rdb-save-incremental-fsync yes

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: redis

View File

@@ -0,0 +1,98 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
labels:
app: redis
namespace: redis
spec:
serviceName: redis
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
initContainers:
- name: config
image: redis:7.0.6
command: [ "sh", "-c" ]
args:
- |
cp /tmp/redis/redis.conf /etc/redis/redis.conf
echo "finding master..."
MASTER_FDQN=`hostname -f | sed -e 's/redis-[0-9]\./redis-0./'`
if [ "$(redis-cli -h sentinel -p 5000 ping)" != "PONG" ]; then
echo "master not found, defaulting to redis-0"
if [ "$(hostname)" = "redis-0" ]; then
echo "this is redis-0, not updating config..."
else
echo "updating redis.conf..."
echo "\nslaveof $MASTER_FDQN 6379" >> /etc/redis/redis.conf
fi
else
echo "sentinel found, finding master"
MASTER="$(redis-cli -h sentinel -p 5000 sentinel get-master-addr-by-name mymaster | grep -E '(^redis-\d{1,})|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})')"
echo "master found : $MASTER, updating redis.conf"
echo "slaveof $MASTER 6379" >> /etc/redis/redis.conf
fi
volumeMounts:
- name: redis-config
mountPath: /etc/redis/
- name: config
mountPath: /tmp/redis/
containers:
- name: redis
image: redis:7.0.6
command: [ "redis-server" ]
args: [ "/etc/redis/redis.conf" ]
ports:
- containerPort: 6379
name: redis
volumeMounts:
- name: data
mountPath: /data
- name: redis-config
mountPath: /etc/redis/
resources:
limits:
memory: 1100Mi
requests:
memory: 1100Mi
volumes:
- name: redis-config
emptyDir: { }
- name: config
configMap:
name: redis-config
volumeClaimTemplates:
- metadata:
name: data
spec:
storageClassName: hostpath
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: redis # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: redis
namespace: redis
spec:
selector:
app: redis # The service exposes Pods with label `app=redis`
ports:
- name: redis-port
port: 6379
nodePort: 30079
type: NodePort

View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: kube-ruoyi

View File

@@ -0,0 +1,41 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruoyi-sentinel
namespace: kube-ruoyi
spec:
replicas: 1
selector:
matchLabels:
app: ruoyi-sentinel
template:
metadata:
labels:
app: ruoyi-sentinel
spec:
containers:
- name: ruoyi-sentinel
image: bladex/sentinel-dashboard
imagePullPolicy: Always
ports:
- containerPort: 8858
env: # Environment variables supplied to the Pod
- name: JAVA_TOOL_OPTIONS
value: "-Dserver.port=8858 -Dcsp.sentinel.dashboard.server=localhost:8858 -Dproject.name=sentinel-dashboard"
---
apiVersion: v1
kind: Service
metadata:
name: ruoyi-sentinel
namespace: kube-ruoyi
labels:
name: ruoyi-sentinel
spec:
type: NodePort
ports:
- port: 8858
targetPort: 8858
nodePort: 30858
selector:
app: ruoyi-sentinel

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-auth # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-auth
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-auth
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-auth
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-auth-server
image: ruoyi-auth:3.6.2
ports:
- name: http
containerPort: 9200 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-auth
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-auth # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-auth
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-auth # The service exposes Pods with label `app=ruoyi-auth`
ports: # Forward incoming connections on port 9200 to the target port 9200
- name: http
port: 9200
targetPort: 9200

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-gateway # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-gateway
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-gateway
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-gateway
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-gateway-server
image: ruoyi-gateway:3.6.2
ports:
- name: http
containerPort: 8080 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-gateway
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-gateway # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-gateway
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-gateway # The service exposes Pods with label `app=ruoyi-gateway`
ports: # Forward incoming connections on port 8080 to the target port 8080
- name: http
port: 8080
targetPort: 8080

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-file # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-file
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-file
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-file
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-file-server
image: ruoyi-modules-file:3.6.2
ports:
- name: http
containerPort: 9300 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-file
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-file # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-file
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-file # The service exposes Pods with label `app=ruoyi-file`
ports: # Forward incoming connections on port 9300 to the target port 9300
- name: http
port: 9300
targetPort: 9300

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-gen # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-gen
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-gen
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-gen
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-gen-server
image: ruoyi-modules-gen:3.6.2
ports:
- name: http
containerPort: 9202 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-gen
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-gen # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-gen
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-gen # The service exposes Pods with label `app=ruoyi-gen`
ports: # Forward incoming connections on port 9202 to the target port 9202
- name: http
port: 9202
targetPort: 9202

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-job # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-job
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-job
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-job
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-job-server
image: ruoyi-modules-job:3.6.2
ports:
- name: http
containerPort: 9203 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-job
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-job # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-job
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-job # The service exposes Pods with label `app=ruoyi-job`
ports: # Forward incoming connections on port 9203 to the target port 9203
- name: http
port: 9203
targetPort: 9203

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-system # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-system
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-system
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-system
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-system-server
image: ruoyi-modules-system:3.6.2
ports:
- name: http
containerPort: 9201 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-system
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-system # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-system
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-system # The service exposes Pods with label `app=ruoyi-system`
ports: # Forward incoming connections on port 9201 to the target port 9201
- name: http
port: 9201
targetPort: 9201

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-monitor # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-monitor
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-monitor
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-monitor
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-monitor-server
image: ruoyi-visual-monitor:3.6.2
ports:
- name: http
containerPort: 9100 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-monitor
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-monitor # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-monitor
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-monitor # The service exposes Pods with label `app=ruoyi-monitor`
ports: # Forward incoming connections on port 9100 to the target port 9100
- name: http
port: 9100
targetPort: 9100

View File

@@ -0,0 +1,37 @@
# Tomcat
server:
port: 8080
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}
sentinel:
# 取消控制台懒加载
eager: true
transport:
# 控制台地址
dashboard: 127.0.0.1:8718
# nacos配置持久化
datasource:
ds1:
nacos:
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
dataId: sentinel-ruoyi-gateway
groupId: DEFAULT_GROUP
data-type: json
rule-type: gw-flow

View File

@@ -0,0 +1,15 @@
# 基础镜像
FROM openjdk:8-jre
# author
MAINTAINER ruoyi
# 挂载目录
VOLUME /home/ruoyi
# 创建目录
RUN mkdir -p /home/ruoyi
# 指定路径
WORKDIR /home/ruoyi
# 复制jar文件到路径
COPY ./jar/ruoyi-gateway.jar /home/ruoyi/ruoyi-gateway.jar
# 启动网关服务
ENTRYPOINT ["java","-jar","ruoyi-gateway.jar"]

View File

@@ -0,0 +1 @@
存放网关模块打包好的jar文件用于docker启动应用。

View File

@@ -0,0 +1,73 @@
apiVersion: apps/v1 # API version
kind: Deployment # Type of kubernetes resource
metadata:
name: ruoyi-system # Name of the kubernetes resource
namespace: kube-ruoyi
labels: # Labels that will be applied to this resource
app: ruoyi-system
spec:
replicas: 1 # No. of replicas/pods to run in this deployment
selector:
matchLabels: # The deployment applies to any pods matching the specified labels
app: ruoyi-system
template: # Template for creating the pods in this deployment
metadata:
labels: # Labels that will be applied to each Pod in this deployment
app: ruoyi-system
spec: # Spec for the containers that will be run in the Pods
containers:
- name: ruoyi-system-server
image: ruoyi-modules-system:3.6.2
ports:
- name: http
containerPort: 9201 # The port that the container exposes
env: # Environment variables supplied to the Pod
- name: SPRING_PROFILES_ACTIVE
value: k8s
- name: SERVER_NAME
value: ruoyi-system
- name: NACOS_SERVER
value: ruoyi-nacos # nacos svc name
- name: NACOS_PORT
value: "8848"
- name: NACOS_SHARED_CONFIGS
value: application-dev.yml
- name: JAVA_OPTS
value: -javaagent:/javaagent/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=k8s::$(SERVER_NAME) -Dskywalking.collector.backend_service=skywalking:11800
volumeMounts:
- mountPath: /javaagent
name: agent-jar
volumes:
- emptyDir: { }
name: agent-jar
initContainers:
# 官网用脚本命令行+args的方式执行多条command语句
- command: ['sh']
args:
- "-c"
- |
cp -r /opt/skywalking-agent /javaagent
chown -R 65534:65534 /javaagent
/bin/chmod -R 777 /javaagent
image: skywalking-agent:8.14.0
imagePullPolicy: IfNotPresent
name: skywalking-agent
volumeMounts:
- mountPath: /javaagent
name: agent-jar
---
apiVersion: v1 # API version
kind: Service # Type of the kubernetes resource
metadata:
name: ruoyi-system # Name of the kubernetes resource
labels: # Labels that will be applied to this resource
app: ruoyi-system
namespace: kube-ruoyi
spec:
type: NodePort # The service will be exposed by opening a Port on each node and proxying it.
selector:
app: ruoyi-system # The service exposes Pods with label `app=ruoyi-system`
ports: # Forward incoming connections on port 9201 to the target port 9201
- name: http
port: 9201
targetPort: 9201

View File

@@ -0,0 +1,17 @@
## cat Dcokerfile
FROM docker.io/library/busybox:latest AS base
# 使用 ADD 下载 java-agent,你也可以使用其他下载命令,或者下载到本地,再 使用 COPY或者ADD 指令添加到 镜像里
ADD https://dlcdn.apache.org/skywalking/java-agent/9.0.0/apache-skywalking-java-agent-9.0.0.tgz /tmp/
RUN mkdir -p /opt \
&& tar -xzf /tmp/apache-skywalking-java-agent-9.0.0.tgz -C /opt/ \
&& rm -rf /tmp/*
#ADD skywalking-agent.tar.gz /opt/
RUN mkdir -p /javaagent
## java-agent 使用 方法
## https://skywalking.apache.org/docs/skywalking-java/next/en/setup/service-agent/java-agent/readme/
## java -javaagent:/opt/skywalking-agent/skywalking-agent.jar -jar yourApp.jar
## -javaagent:/opt/skywalking-agent/skywalking-agent.jar=agent.service_name=yourAppName,collector.backend_service=127.0.0.1:11800
## -javaagent:/opt/skywalking-agent/skywalking-agent.jar -Dskywalking.agent.service_name=yourAppName -Dskywalking.collector.backend_service=127.0.0.1:11800

View File

@@ -0,0 +1,44 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: elasticsearch
name: elasticsearch
namespace: kube-ruoyi
spec:
replicas: 1
selector:
matchLabels:
app: elasticsearch
template:
metadata:
labels:
app: elasticsearch
spec:
containers:
- name: elasticsearch
image: elasticsearch:7.14.2
ports:
- containerPort: 9200
name: cluster-node
env:
- name: discovery.type
value: single-node
- name: TZ
value: Asia/Shanghai
- name: ES_JAVA_OPTS
value: -Xms512m -Xmx512m
---
apiVersion: v1
kind: Service
metadata:
name: elasticsearch
namespace: kube-ruoyi
spec:
ports:
- port: 9220 # 和auth-server的端口冲突了对外暴露换一个端口访问
targetPort: 9200
name: cluster-node
selector:
app: elasticsearch # 该 Service 会将所有具有标签 app: mysql-labels-app暴露到一个抽象的 Service 端口上targetPort容器接收流量的端口port可任意取值的抽象的 Service 端口,其他 Pod 通过该端口访问 Service
type: NodePort

View File

@@ -0,0 +1,50 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: skywalking
name: skywalking
namespace: kube-ruoyi
spec:
replicas: 1
selector:
matchLabels:
app: skywalking
template:
metadata:
labels:
app: skywalking
spec:
containers:
- name: skywalking
image: apache/skywalking-oap-server
imagePullPolicy: Always
ports:
- containerPort: 11800
name: collector
- containerPort: 12800
name: oap
env:
- name: SW_STORAGE
value: elasticsearch
- name: TZ
value: Asia/Shanghai
- name: SW_STORAGE_ES_CLUSTER_NODES
value: elasticsearch:9220
---
apiVersion: v1
kind: Service
metadata:
name: skywalking
namespace: kube-ruoyi
spec:
ports:
- port: 11800
targetPort: 11800
name: collector
- port: 12800
targetPort: 12800
name: oap
selector:
app: skywalking # 该 Service 会将所有具有标签 app: mysql-labels-app暴露到一个抽象的 Service 端口上targetPort容器接收流量的端口port可任意取值的抽象的 Service 端口,其他 Pod 通过该端口访问 Service
type: NodePort

View File

@@ -0,0 +1,42 @@
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
name: skywalking-ui
name: skywalking-ui
namespace: kube-ruoyi
spec:
replicas: 1
selector:
matchLabels:
app: skywalking-ui
template:
metadata:
labels:
app: skywalking-ui
spec:
containers:
- name: skywalking-ui
image: apache/skywalking-ui
imagePullPolicy: Always
ports:
- containerPort: 8080
name: console
env:
- name: SW_OAP_ADDRESS
value: http://skywalking:12800
- name: TZ
value: Asia/Shanghai
---
apiVersion: v1
kind: Service
metadata:
name: skywalking-ui
namespace: kube-ruoyi
spec:
ports:
- port: 8080
nodePort: 30088
selector:
app: skywalking-ui # 该 Service 会将所有具有标签 app: mysql-labels-app暴露到一个抽象的 Service 端口上targetPort容器接收流量的端口port可任意取值的抽象的 Service 端口,其他 Pod 通过该端口访问 Service
type: NodePort

View File

@@ -9,7 +9,7 @@ usage() {
# copy sql
echo "begin copy sql "
cp ../sql/ry_20250523.sql ./mysql/db
cp ../sql/ry_20240629.sql ./mysql/db
cp ../sql/ry_config_20250224.sql ./mysql/db
# copy html

11
pom.xml
View File

@@ -6,14 +6,14 @@
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
<name>ruoyi</name>
<url>http://www.ruoyi.vip</url>
<description>若依微服务系统</description>
<properties>
<ruoyi.version>3.6.6</ruoyi.version>
<ruoyi.version>3.6.5</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
@@ -26,16 +26,17 @@
<pagehelper.boot.version>2.0.0</pagehelper.boot.version>
<druid.version>1.2.23</druid.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<commons.io.version>2.19.0</commons.io.version>
<commons.io.version>2.13.0</commons.io.version>
<velocity.version>2.3</velocity.version>
<fastjson.version>2.0.57</fastjson.version>
<fastjson.version>2.0.53</fastjson.version>
<jjwt.version>0.9.1</jjwt.version>
<minio.version>8.2.2</minio.version>
<poi.version>4.1.2</poi.version>
<springdoc.version>1.6.9</springdoc.version>
<transmittable-thread-local.version>2.14.4</transmittable-thread-local.version>
<!-- override dependency version -->
<tomcat.version>9.0.105</tomcat.version>
<tomcat.version>9.0.98</tomcat.version>
<logback.version>1.2.13</logback.version>
<spring-framework.version>5.3.39</spring-framework.version>
</properties>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -56,8 +56,8 @@ public class SysUser extends BaseEntity
/** 密码 */
private String password;
/** 号状态0正常 1停用 */
@Excel(name = "号状态", readConverterExp = "0=正常,1=停用")
/** 号状态0正常 1停用 */
@Excel(name = "号状态", readConverterExp = "0=正常,1=停用")
private String status;
/** 删除标志0代表存在 2代表删除 */
@@ -71,9 +71,6 @@ public class SysUser extends BaseEntity
@Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
private Date loginDate;
/** 密码最后更新时间 */
private Date pwdUpdateDate;
/** 部门对象 */
@Excels({
@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
@@ -251,16 +248,6 @@ public class SysUser extends BaseEntity
this.loginDate = loginDate;
}
public Date getPwdUpdateDate()
{
return pwdUpdateDate;
}
public void setPwdUpdateDate(Date pwdUpdateDate)
{
this.pwdUpdateDate = pwdUpdateDate;
}
public SysDept getDept()
{
return dept;
@@ -310,7 +297,6 @@ public class SysUser extends BaseEntity
{
this.roleId = roleId;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
@@ -327,7 +313,6 @@ public class SysUser extends BaseEntity
.append("delFlag", getDelFlag())
.append("loginIp", getLoginIp())
.append("loginDate", getLoginDate())
.append("pwdUpdateDate", getPwdUpdateDate())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -143,7 +143,6 @@ public class SysLoginService
SysUser sysUser = new SysUser();
sysUser.setUserName(username);
sysUser.setNickName(username);
sysUser.setPwdUpdateDate(DateUtils.getNowDate());
sysUser.setPassword(SecurityUtils.encryptPassword(password));
R<?> registerResult = remoteUserService.registerUserInfo(sysUser, SecurityConstants.INNER);

View File

@@ -0,0 +1,22 @@
# Tomcat
server:
port: 9200
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}

View File

@@ -9,7 +9,7 @@ spring:
name: ruoyi-auth
profiles:
# 环境配置
active: dev
active: ${SPRING_PROFILES_ACTIVE:dev}
cloud:
nacos:
discovery:

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -136,14 +136,6 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return new Date(time);
}
/**
* 计算相差天数
*/
public static int differentDaysByMillisecond(Date date1, Date date2)
{
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
}
/**
* 计算时间差
*

View File

@@ -390,7 +390,7 @@ public class ExcelUtil<T>
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (s.matches("^\\d+\\.0$"))
if (StringUtils.endsWith(s, ".0"))
{
val = StringUtils.substringBefore(s, ".0");
}

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,87 @@
package com.ruoyi.gateway.filter;
import java.util.Collections;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 获取body请求数据解决流不能重复读取问题
*
* @author ruoyi
*/
@Component
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
{
public CacheRequestFilter()
{
super(Config.class);
}
@Override
public String name()
{
return "CacheRequestFilter";
}
@Override
public GatewayFilter apply(Config config)
{
CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
Integer order = config.getOrder();
if (order == null)
{
return cacheRequestGatewayFilter;
}
return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
}
public static class CacheRequestGatewayFilter implements GatewayFilter
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
// GET DELETE 不过滤
HttpMethod method = exchange.getRequest().getMethod();
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
{
return chain.filter(exchange);
}
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
if (serverHttpRequest == exchange.getRequest())
{
return chain.filter(exchange);
}
return chain.filter(exchange.mutate().request(serverHttpRequest).build());
});
}
}
@Override
public List<String> shortcutFieldOrder()
{
return Collections.singletonList("order");
}
static class Config
{
private Integer order;
public Integer getOrder()
{
return order;
}
public void setOrder(Integer order)
{
this.order = order;
}
}
}

View File

@@ -0,0 +1,37 @@
# Tomcat
server:
port: 8080
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}
sentinel:
# 取消控制台懒加载
eager: true
transport:
# 控制台地址
dashboard: 127.0.0.1:8718
# nacos配置持久化
datasource:
ds1:
nacos:
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
dataId: sentinel-ruoyi-gateway
groupId: DEFAULT_GROUP
data-type: json
rule-type: gw-flow

View File

@@ -9,7 +9,7 @@ spring:
name: ruoyi-gateway
profiles:
# 环境配置
active: dev
active: ${SPRING_PROFILES_ACTIVE:dev}
cloud:
nacos:
discovery:

View File

@@ -4,7 +4,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,23 @@
# Tomcat
server:
port: 9300
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}

View File

@@ -9,7 +9,7 @@ spring:
name: ruoyi-file
profiles:
# 环境配置
active: dev
active: ${SPRING_PROFILES_ACTIVE:dev}
cloud:
nacos:
discovery:

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,23 @@
# Tomcat
server:
port: 9202
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}

View File

@@ -9,7 +9,7 @@ spring:
name: ruoyi-gen
profiles:
# 环境配置
active: dev
active: ${SPRING_PROFILES_ACTIVE:dev}
cloud:
nacos:
discovery:

View File

@@ -283,9 +283,9 @@
</template>
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
name: "${BusinessName}",
@@ -346,18 +346,18 @@ export default {
#end
#end
}
}
};
},
created() {
this.getList()
this.getList();
},
methods: {
/** 查询${functionName}列表 */
getList() {
this.loading = true
this.loading = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {}
this.queryParams.params = {};
#break
#end
#end
@@ -365,40 +365,40 @@ export default {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
}
#end
#end
list${BusinessName}(this.queryParams).then(response => {
this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
this.loading = false
})
this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
this.loading = false;
});
},
/** 转换${functionName}数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children
delete node.children;
}
return {
id: node.${treeCode},
label: node.${treeName},
children: node.children
}
};
},
/** 查询${functionName}下拉树结构 */
getTreeselect() {
list${BusinessName}().then(response => {
this.${businessName}Options = []
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
this.${businessName}Options.push(data)
})
this.${businessName}Options = [];
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
this.${businessName}Options.push(data);
});
},
// 取消按钮
cancel() {
this.open = false
this.reset()
this.open = false;
this.reset();
},
// 表单重置
reset() {
@@ -410,61 +410,61 @@ export default {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
}
this.resetForm("form")
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.getList()
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
this.daterange${AttrName} = []
this.daterange${AttrName} = [];
#end
#end
this.resetForm("queryForm")
this.handleQuery()
this.resetForm("queryForm");
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset()
this.getTreeselect()
this.reset();
this.getTreeselect();
if (row != null && row.${treeCode}) {
this.form.${treeParentCode} = row.${treeCode}
this.form.${treeParentCode} = row.${treeCode};
} else {
this.form.${treeParentCode} = 0
this.form.${treeParentCode} = 0;
}
this.open = true
this.title = "添加${functionName}"
this.open = true;
this.title = "添加${functionName}";
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false
this.isExpandAll = !this.isExpandAll
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true
})
this.refreshTable = true;
});
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.getTreeselect()
this.reset();
this.getTreeselect();
if (row != null) {
this.form.${treeParentCode} = row.${treeParentCode}
this.form.${treeParentCode} = row.${treeParentCode};
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.form = response.data
this.form = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end
#end
this.open = true
this.title = "修改${functionName}"
})
this.open = true;
this.title = "修改${functionName}";
});
},
/** 提交按钮 */
submitForm() {
@@ -472,34 +472,34 @@ export default {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("修改成功")
this.open = false
this.getList()
})
this.#[[$modal]]#.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
add${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("新增成功")
this.open = false
this.getList()
})
this.#[[$modal]]#.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
})
});
},
/** 删除按钮操作 */
handleDelete(row) {
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
return del${BusinessName}(row.${pkColumn.javaField})
return del${BusinessName}(row.${pkColumn.javaField});
}).then(() => {
this.getList()
this.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
this.getList();
this.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
}
}
}
};
</script>

View File

@@ -353,7 +353,7 @@
</template>
<script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
export default {
name: "${BusinessName}",
@@ -423,18 +423,18 @@ export default {
#end
#end
}
}
};
},
created() {
this.getList()
this.getList();
},
methods: {
/** 查询${functionName}列表 */
getList() {
this.loading = true
this.loading = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {}
this.queryParams.params = {};
#break
#end
#end
@@ -442,21 +442,21 @@ export default {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
}
#end
#end
list${BusinessName}(this.queryParams).then(response => {
this.${businessName}List = response.rows
this.total = response.total
this.loading = false
})
this.${businessName}List = response.rows;
this.total = response.total;
this.loading = false;
});
},
// 取消按钮
cancel() {
this.open = false
this.reset()
this.open = false;
this.reset();
},
// 表单重置
reset() {
@@ -468,27 +468,27 @@ export default {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
}
};
#if($table.sub)
this.${subclassName}List = []
this.${subclassName}List = [];
#end
this.resetForm("form")
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
this.daterange${AttrName} = []
this.daterange${AttrName} = [];
#end
#end
this.resetForm("queryForm")
this.handleQuery()
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
@@ -498,27 +498,27 @@ export default {
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加${functionName}"
this.reset();
this.open = true;
this.title = "添加${functionName}";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset()
this.reset();
const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
get${BusinessName}(${pkColumn.javaField}).then(response => {
this.form = response.data
this.form = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(",")
this.form.$column.javaField = this.form.${column.javaField}.split(",");
#end
#end
#if($table.sub)
this.${subclassName}List = response.data.${subclassName}List
this.${subclassName}List = response.data.${subclassName}List;
#end
this.open = true
this.title = "修改${functionName}"
})
this.open = true;
this.title = "修改${functionName}";
});
},
/** 提交按钮 */
submitForm() {
@@ -526,64 +526,64 @@ export default {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(",")
this.form.$column.javaField = this.form.${column.javaField}.join(",");
#end
#end
#if($table.sub)
this.form.${subclassName}List = this.${subclassName}List
this.form.${subclassName}List = this.${subclassName}List;
#end
if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("修改成功")
this.open = false
this.getList()
})
this.#[[$modal]]#.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
add${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("新增成功")
this.open = false
this.getList()
})
this.#[[$modal]]#.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
})
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(${pkColumn.javaField}s)
return del${BusinessName}(${pkColumn.javaField}s);
}).then(() => {
this.getList()
this.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
this.getList();
this.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
},
#if($table.sub)
/** ${subTable.functionName}序号 */
row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1
row.index = rowIndex + 1;
},
/** ${subTable.functionName}添加按钮操作 */
handleAdd${subClassName}() {
let obj = {}
let obj = {};
#foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
obj.$column.javaField = ""
obj.$column.javaField = "";
#end
#end
this.${subclassName}List.push(obj)
this.${subclassName}List.push(obj);
},
/** ${subTable.functionName}删除按钮操作 */
handleDelete${subClassName}() {
if (this.checked${subClassName}.length == 0) {
this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
} else {
const ${subclassName}List = this.${subclassName}List
const checked${subClassName} = this.checked${subClassName}
const ${subclassName}List = this.${subclassName}List;
const checked${subClassName} = this.checked${subClassName};
this.${subclassName}List = ${subclassName}List.filter(function(item) {
return checked${subClassName}.indexOf(item.index) == -1
})
});
}
},
/** 复选框选中数据 */
@@ -598,5 +598,5 @@ export default {
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
}
}
}
};
</script>

View File

@@ -271,26 +271,26 @@
</template>
<script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
const { proxy } = getCurrentInstance()
const { proxy } = getCurrentInstance();
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts})
const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
#end
const ${businessName}List = ref([])
const ${businessName}Options = ref([])
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const title = ref("")
const isExpandAll = ref(true)
const refreshTable = ref(true)
const ${businessName}List = ref([]);
const ${businessName}Options = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const isExpandAll = ref(true);
const refreshTable = ref(true);
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([])
const daterange${AttrName} = ref([]);
#end
#end
@@ -318,16 +318,16 @@ const data = reactive({
#end
#end
}
})
});
const { queryParams, form, rules } = toRefs(data)
const { queryParams, form, rules } = toRefs(data);
/** 查询${functionName}列表 */
function getList() {
loading.value = true
loading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
queryParams.value.params = {}
queryParams.value.params = {};
#break
#end
#end
@@ -335,31 +335,31 @@ function getList() {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != daterange${AttrName} && '' != daterange${AttrName}) {
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
}
#end
#end
list${BusinessName}(queryParams.value).then(response => {
${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}")
loading.value = false
})
${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
loading.value = false;
});
}
/** 查询${functionName}下拉树结构 */
function getTreeselect() {
list${BusinessName}().then(response => {
${businessName}Options.value = []
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}")
${businessName}Options.value.push(data)
})
${businessName}Options.value = [];
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
${businessName}Options.value.push(data);
});
}
// 取消按钮
function cancel() {
open.value = false
reset()
open.value = false;
reset();
}
// 表单重置
@@ -372,13 +372,13 @@ function reset() {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
}
proxy.resetForm("${businessName}Ref")
};
proxy.resetForm("${businessName}Ref");
}
/** 搜索按钮操作 */
function handleQuery() {
getList()
getList();
}
/** 重置按钮操作 */
@@ -386,52 +386,52 @@ function resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
daterange${AttrName}.value = []
daterange${AttrName}.value = [];
#end
#end
proxy.resetForm("queryRef")
handleQuery()
proxy.resetForm("queryRef");
handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
reset()
getTreeselect()
reset();
getTreeselect();
if (row != null && row.${treeCode}) {
form.value.${treeParentCode} = row.${treeCode}
form.value.${treeParentCode} = row.${treeCode};
} else {
form.value.${treeParentCode} = 0
form.value.${treeParentCode} = 0;
}
open.value = true
title.value = "添加${functionName}"
open.value = true;
title.value = "添加${functionName}";
}
/** 展开/折叠操作 */
function toggleExpandAll() {
refreshTable.value = false
isExpandAll.value = !isExpandAll.value
refreshTable.value = false;
isExpandAll.value = !isExpandAll.value;
nextTick(() => {
refreshTable.value = true
})
refreshTable.value = true;
});
}
/** 修改按钮操作 */
async function handleUpdate(row) {
reset()
await getTreeselect()
reset();
await getTreeselect();
if (row != null) {
form.value.${treeParentCode} = row.${treeParentCode}
form.value.${treeParentCode} = row.${treeParentCode};
}
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
form.value = response.data
form.value = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(",")
form.value.$column.javaField = form.value.${column.javaField}.split(",");
#end
#end
open.value = true
title.value = "修改${functionName}"
})
open.value = true;
title.value = "修改${functionName}";
});
}
/** 提交按钮 */
@@ -440,35 +440,35 @@ function submitForm() {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(",")
form.value.$column.javaField = form.value.${column.javaField}.join(",");
#end
#end
if (form.value.${pkColumn.javaField} != null) {
update${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("修改成功")
open.value = false
getList()
})
proxy.#[[$modal]]#.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
add${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("新增成功")
open.value = false
getList()
})
proxy.#[[$modal]]#.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
})
});
}
/** 删除按钮操作 */
function handleDelete(row) {
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
return del${BusinessName}(row.${pkColumn.javaField})
return del${BusinessName}(row.${pkColumn.javaField});
}).then(() => {
getList()
proxy.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
getList();
proxy.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
}
getList()
getList();
</script>

View File

@@ -343,33 +343,33 @@
</template>
<script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
const { proxy } = getCurrentInstance()
const { proxy } = getCurrentInstance();
#if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts})
const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
#end
const ${businessName}List = ref([])
const ${businessName}List = ref([]);
#if($table.sub)
const ${subclassName}List = ref([])
const ${subclassName}List = ref([]);
#end
const open = ref(false)
const loading = ref(true)
const showSearch = ref(true)
const ids = ref([])
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref([]);
#if($table.sub)
const checked${subClassName} = ref([])
const checked${subClassName} = ref([]);
#end
const single = ref(true)
const multiple = ref(true)
const total = ref(0)
const title = ref("")
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("");
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([])
const daterange${AttrName} = ref([]);
#end
#end
@@ -399,16 +399,16 @@ const data = reactive({
#end
#end
}
})
});
const { queryParams, form, rules } = toRefs(data)
const { queryParams, form, rules } = toRefs(data);
/** 查询${functionName}列表 */
function getList() {
loading.value = true
loading.value = true;
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
queryParams.value.params = {}
queryParams.value.params = {};
#break
#end
#end
@@ -416,22 +416,22 @@ function getList() {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != daterange${AttrName} && '' != daterange${AttrName}) {
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
}
#end
#end
list${BusinessName}(queryParams.value).then(response => {
${businessName}List.value = response.rows
total.value = response.total
loading.value = false
})
${businessName}List.value = response.rows;
total.value = response.total;
loading.value = false;
});
}
// 取消按钮
function cancel() {
open.value = false
reset()
open.value = false;
reset();
}
// 表单重置
@@ -444,17 +444,17 @@ function reset() {
$column.javaField: null#if($foreach.count != $columns.size()),#end
#end
#end
}
};
#if($table.sub)
${subclassName}List.value = []
${subclassName}List.value = [];
#end
proxy.resetForm("${businessName}Ref")
proxy.resetForm("${businessName}Ref");
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNum = 1
getList()
queryParams.value.pageNum = 1;
getList();
}
/** 重置按钮操作 */
@@ -462,44 +462,44 @@ function resetQuery() {
#foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
daterange${AttrName}.value = []
daterange${AttrName}.value = [];
#end
#end
proxy.resetForm("queryRef")
handleQuery()
proxy.resetForm("queryRef");
handleQuery();
}
// 多选框选中数据
function handleSelectionChange(selection) {
ids.value = selection.map(item => item.${pkColumn.javaField})
single.value = selection.length != 1
multiple.value = !selection.length
ids.value = selection.map(item => item.${pkColumn.javaField});
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 新增按钮操作 */
function handleAdd() {
reset()
open.value = true
title.value = "添加${functionName}"
reset();
open.value = true;
title.value = "添加${functionName}";
}
/** 修改按钮操作 */
function handleUpdate(row) {
reset()
reset();
const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
get${BusinessName}(_${pkColumn.javaField}).then(response => {
form.value = response.data
form.value = response.data;
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(",")
form.value.$column.javaField = form.value.${column.javaField}.split(",");
#end
#end
#if($table.sub)
${subclassName}List.value = response.data.${subclassName}List
${subclassName}List.value = response.data.${subclassName}List;
#end
open.value = true
title.value = "修改${functionName}"
})
open.value = true;
title.value = "修改${functionName}";
});
}
/** 提交按钮 */
@@ -508,68 +508,68 @@ function submitForm() {
if (valid) {
#foreach ($column in $columns)
#if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(",")
form.value.$column.javaField = form.value.${column.javaField}.join(",");
#end
#end
#if($table.sub)
form.value.${subclassName}List = ${subclassName}List.value
form.value.${subclassName}List = ${subclassName}List.value;
#end
if (form.value.${pkColumn.javaField} != null) {
update${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("修改成功")
open.value = false
getList()
})
proxy.#[[$modal]]#.msgSuccess("修改成功");
open.value = false;
getList();
});
} else {
add${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("新增成功")
open.value = false
getList()
})
proxy.#[[$modal]]#.msgSuccess("新增成功");
open.value = false;
getList();
});
}
}
})
});
}
/** 删除按钮操作 */
function handleDelete(row) {
const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value
const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(_${pkColumn.javaField}s)
return del${BusinessName}(_${pkColumn.javaField}s);
}).then(() => {
getList()
proxy.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {})
getList();
proxy.#[[$modal]]#.msgSuccess("删除成功");
}).catch(() => {});
}
#if($table.sub)
/** ${subTable.functionName}序号 */
function row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1
row.index = rowIndex + 1;
}
/** ${subTable.functionName}添加按钮操作 */
function handleAdd${subClassName}() {
let obj = {}
let obj = {};
#foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField)
obj.$column.javaField = ""
obj.$column.javaField = "";
#end
#end
${subclassName}List.value.push(obj)
${subclassName}List.value.push(obj);
}
/** ${subTable.functionName}删除按钮操作 */
function handleDelete${subClassName}() {
if (checked${subClassName}.value.length == 0) {
proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
} else {
const ${subclassName}s = ${subclassName}List.value
const checked${subClassName}s = checked${subClassName}.value
const ${subclassName}s = ${subclassName}List.value;
const checked${subClassName}s = checked${subClassName}.value;
${subclassName}List.value = ${subclassName}s.filter(function(item) {
return checked${subClassName}s.indexOf(item.index) == -1
})
});
}
}
@@ -586,5 +586,5 @@ function handleExport() {
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
}
getList()
getList();
</script>

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,22 @@
# Tomcat
server:
port: 9203
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}

View File

@@ -9,7 +9,7 @@ spring:
name: ruoyi-job
profiles:
# 环境配置
active: dev
active: ${SPRING_PROFILES_ACTIVE:dev}
cloud:
nacos:
discovery:

View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId>
<version>3.6.6</version>
<version>3.6.5</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -12,7 +12,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.MimeTypeUtils;
@@ -113,8 +112,7 @@ public class SysProfileController extends BaseController
newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(userName, newPassword) > 0)
{
// 更新缓存用户密码&密码最后更新时间
loginUser.getSysUser().setPwdUpdateDate(DateUtils.getNowDate());
// 更新缓存用户密码
loginUser.getSysUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser);
return success();

View File

@@ -1,7 +1,6 @@
package com.ruoyi.system.controller;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@@ -19,8 +18,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
@@ -189,35 +186,9 @@ public class SysUserController extends BaseController
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
return ajax;
}
// 检查初始密码是否提醒修改
public boolean initPasswordIsModify(Date pwdUpdateDate)
{
Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
}
// 检查密码是否过期
public boolean passwordIsExpiration(Date pwdUpdateDate)
{
Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
if (passwordValidateDays != null && passwordValidateDays > 0)
{
if (StringUtils.isNull(pwdUpdateDate))
{
// 如果从未修改过初始密码,直接提醒过期
return true;
}
Date nowDate = DateUtils.getNowDate();
return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
}
return false;
}
/**
* 根据用户编号获取详细信息
*/

View File

@@ -0,0 +1,22 @@
# Tomcat
server:
port: 9201
# Spring
spring:
application:
# 应用名称
name: ${SERVER_NAME}
cloud:
nacos:
discovery:
# 服务注册地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
config:
# 配置中心地址
server-addr: ${NACOS_SERVER}:${NACOS_PORT}
# 配置文件格式
file-extension: yml
# 共享配置
shared-configs:
- ${NACOS_SHARED_CONFIGS}

View File

@@ -9,7 +9,7 @@ spring:
name: ruoyi-system
profiles:
# 环境配置
active: dev
active: ${SPRING_PROFILES_ACTIVE:dev}
cloud:
nacos:
discovery:

View File

@@ -5,25 +5,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.ruoyi.system.mapper.SysUserMapper">
<resultMap type="SysUser" id="SysUserResult">
<id property="userId" column="user_id" />
<result property="deptId" column="dept_id" />
<result property="userName" column="user_name" />
<result property="nickName" column="nick_name" />
<result property="email" column="email" />
<result property="phonenumber" column="phonenumber" />
<result property="sex" column="sex" />
<result property="avatar" column="avatar" />
<result property="password" column="password" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="loginIp" column="login_ip" />
<result property="loginDate" column="login_date" />
<result property="pwdUpdateDate" column="pwd_update_date" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<id property="userId" column="user_id" />
<result property="deptId" column="dept_id" />
<result property="userName" column="user_name" />
<result property="nickName" column="nick_name" />
<result property="email" column="email" />
<result property="phonenumber" column="phonenumber" />
<result property="sex" column="sex" />
<result property="avatar" column="avatar" />
<result property="password" column="password" />
<result property="status" column="status" />
<result property="delFlag" column="del_flag" />
<result property="loginIp" column="login_ip" />
<result property="loginDate" column="login_date" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
<result property="remark" column="remark" />
<association property="dept" javaType="SysDept" resultMap="deptResult" />
<collection property="roles" javaType="java.util.List" resultMap="RoleResult" />
</resultMap>
@@ -48,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectUserVo">
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.remark,
select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
from sys_user u
@@ -155,7 +154,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sex != null and sex != ''">sex,</if>
<if test="password != null and password != ''">password,</if>
<if test="status != null and status != ''">status,</if>
<if test="pwdUpdateDate != null">pwd_update_date,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
create_time
@@ -170,7 +168,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="sex != null and sex != ''">#{sex},</if>
<if test="password != null and password != ''">#{password},</if>
<if test="status != null and status != ''">#{status},</if>
<if test="pwdUpdateDate != null">#{pwdUpdateDate},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
sysdate()
@@ -206,7 +203,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</update>
<update id="resetUserPwd" parameterType="SysUser">
update sys_user set pwd_update_date = sysdate(), password = #{password} where user_name = #{userName}
update sys_user set password = #{password} where user_name = #{userName}
</update>
<delete id="deleteUserById" parameterType="Long">

10
ruoyi-ui/.eslintignore Normal file
View File

@@ -0,0 +1,10 @@
# 忽略build目录下类型为js的文件的语法检查
build/*.js
# 忽略src/assets目录下文件的语法检查
src/assets
# 忽略public目录下文件的语法检查
public
# 忽略当前目录下为js的文件的语法检查
*.js
# 忽略当前目录下为vue的文件的语法检查
*.vue

199
ruoyi-ui/.eslintrc.js Normal file
View File

@@ -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']
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "ruoyi",
"version": "3.6.6",
"version": "3.6.5",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
@@ -8,7 +8,19 @@
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview"
"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",
@@ -44,17 +56,24 @@
"vue": "2.6.12",
"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": "6.1.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",

View File

@@ -6,12 +6,20 @@
</template>
<script>
import ThemePicker from "@/components/ThemePicker"
import ThemePicker from "@/components/ThemePicker";
export default {
name: "App",
components: { ThemePicker }
}
components: { ThemePicker },
metaInfo() {
return {
title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
titleTemplate: title => {
return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
}
}
}
};
</script>
<style scoped>
#app .theme-picker {

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746590936918" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" xmlns:xlink="http://www.w3.org/1999/xlink" width="233.203125" height="200"><path d="M1151.9144 325.11999969V89.12a57.04000031 57.04000031 0 0 0-28.8-49.44 58.15999969 58.15999969 0 0 0-57.76000031 0 57.04000031 57.04000031 0 0 0-28.8 49.44v235.99999969c0.24 84.31999969-33.6 152.56000031-94.08 212.00000062-60.07999969 59.83999969-141.84 80.64-227.04 80.4H225.91440031L388.07439969 457.11999969a56.80000031 56.80000031 0 0 0 12.40000031-62.16 57.76000031 57.76000031 0 0 0-94.00000031-18.63999938L48.8744 631.20000031a56.88 56.88 0 0 0 0 80.79999938l264.96 262.56a58.08 58.08 0 0 0 96.55999969-25.59999938 56.80000031 56.80000031 0 0 0-14.95999969-55.2L232.07439969 731.67999969h483.44000062c116.56000031 0 226.15999969-32.08000031 308.64-113.76 82.15999969-80.80000031 128.23999969-178.15999969 127.83999938-292.87999969" p-id="5379"></path></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746760911144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12537" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M395.21211 182.914448c0 62.669318 49.541323 113.472378 110.642936 113.472378 61.093427 0 110.652146-50.80306 110.65214601-113.472378 0-62.685691-49.559742-113.487727-110.65214601-113.487727C444.75241 69.426721 395.21211 120.22978 395.21211 182.914448zM395.21211 523.34693101c0 62.668295 49.541323 113.487727 110.642936 113.48772699 61.093427 0 110.652146-50.820456 110.652146-113.487727 0-62.669318-49.559742-113.472378-110.652146-113.472378C444.75241 409.874553 395.21211 460.67761301 395.21211 523.34693101zM395.21211 841.084529c0 62.686714 49.541323 113.488751 110.642936 113.488751 61.093427 0 110.652146-50.80203599 110.65214601-113.488751 0-62.669318-49.559742-113.471354-110.65214601-113.471354C444.75241 727.614198 395.21211 778.416234 395.21211 841.084529z" p-id="12538"></path></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -25,7 +25,7 @@
z-index: 1001;
overflow: hidden;
-webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
box-shadow: 2px 0 6px rgba(0,21,41,.35);
// reset element-ui css
.horizontal-collapse-transition {

View File

@@ -71,58 +71,58 @@ export default {
methods: {
// 单选按钮值变化时
radioChange() {
('day rachange')
('day rachange');
if (this.radioValue !== 2 && this.cron.week !== '?') {
this.$emit('update', 'week', '?', 'day')
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'day', '*')
break
this.$emit('update', 'day', '*');
break;
case 2:
this.$emit('update', 'day', '?')
break
this.$emit('update', 'day', '?');
break;
case 3:
this.$emit('update', 'day', this.cycleTotal)
break
this.$emit('update', 'day', this.cycleTotal);
break;
case 4:
this.$emit('update', 'day', this.averageTotal)
break
this.$emit('update', 'day', this.averageTotal);
break;
case 5:
this.$emit('update', 'day', this.workday + 'W')
break
this.$emit('update', 'day', this.workday + 'W');
break;
case 6:
this.$emit('update', 'day', 'L')
break
this.$emit('update', 'day', 'L');
break;
case 7:
this.$emit('update', 'day', this.checkboxString)
break
this.$emit('update', 'day', this.checkboxString);
break;
}
('day rachange end')
('day rachange end');
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'day', this.cycleTotal)
this.$emit('update', 'day', this.cycleTotal);
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'day', this.averageTotal)
this.$emit('update', 'day', this.averageTotal);
}
},
// 最近工作日值变化时
workdayChange() {
if (this.radioValue == '5') {
this.$emit('update', 'day', this.workdayCheck + 'W')
this.$emit('update', 'day', this.workdayCheck + 'W');
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '7') {
this.$emit('update', 'day', this.checkboxString)
this.$emit('update', 'day', this.checkboxString);
}
}
},
@@ -138,23 +138,23 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 1, 30)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 31, 31)
return cycle01 + '-' + cycle02
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 1, 30)
const average02 = this.checkNum(this.average02, 1, 31 - average01 || 0)
return average01 + '/' + average02
return average01 + '/' + average02;
},
// 计算工作日格式
workdayCheck: function () {
const workday = this.checkNum(this.workday, 1, 31)
return workday
return workday;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str == '' ? '*' : str
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}

View File

@@ -51,43 +51,37 @@ export default {
methods: {
// 单选按钮值变化时
radioChange() {
if (this.cron.min === '*') {
this.$emit('update', 'min', '0', 'hour')
}
if (this.cron.second === '*') {
this.$emit('update', 'second', '0', 'hour')
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'hour', '*')
break
this.$emit('update', 'hour', '*')
break;
case 2:
this.$emit('update', 'hour', this.cycleTotal)
break
this.$emit('update', 'hour', this.cycleTotal);
break;
case 3:
this.$emit('update', 'hour', this.averageTotal)
break
this.$emit('update', 'hour', this.averageTotal);
break;
case 4:
this.$emit('update', 'hour', this.checkboxString)
break
this.$emit('update', 'hour', this.checkboxString);
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'hour', this.cycleTotal)
this.$emit('update', 'hour', this.cycleTotal);
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'hour', this.averageTotal)
this.$emit('update', 'hour', this.averageTotal);
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'hour', this.checkboxString)
this.$emit('update', 'hour', this.checkboxString);
}
}
},
@@ -102,18 +96,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 22)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 23)
return cycle01 + '-' + cycle02
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 22)
const average02 = this.checkNum(this.average02, 1, 23 - average01 || 0)
return average01 + '/' + average02
return average01 + '/' + average02;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str == '' ? '*' : str
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}

View File

@@ -113,14 +113,14 @@
</template>
<script>
import CrontabSecond from "./second.vue"
import CrontabMin from "./min.vue"
import CrontabHour from "./hour.vue"
import CrontabDay from "./day.vue"
import CrontabMonth from "./month.vue"
import CrontabWeek from "./week.vue"
import CrontabYear from "./year.vue"
import CrontabResult from "./result.vue"
import CrontabSecond from "./second.vue";
import CrontabMin from "./min.vue";
import CrontabHour from "./hour.vue";
import CrontabDay from "./day.vue";
import CrontabMonth from "./month.vue";
import CrontabWeek from "./week.vue";
import CrontabYear from "./year.vue";
import CrontabResult from "./result.vue";
export default {
data() {
@@ -137,19 +137,19 @@ export default {
week: "?",
year: "",
},
}
};
},
name: "vcrontab",
props: ["expression", "hideComponent"],
methods: {
shouldHide(key) {
if (this.hideComponent && this.hideComponent.includes(key)) return false
return true
if (this.hideComponent && this.hideComponent.includes(key)) return false;
return true;
},
resolveExp() {
// 反解析 表达式
if (this.expression) {
let arr = this.expression.split(" ")
let arr = this.expression.split(" ");
if (arr.length >= 6) {
//6 位以上是合法表达式
let obj = {
@@ -160,160 +160,160 @@ export default {
month: arr[4],
week: arr[5],
year: arr[6] ? arr[6] : "",
}
};
this.crontabValueObj = {
...obj,
}
};
for (let i in obj) {
if (obj[i]) this.changeRadio(i, obj[i])
if (obj[i]) this.changeRadio(i, obj[i]);
}
}
} else {
// 没有传入的表达式 则还原
this.clearCron()
this.clearCron();
}
},
// tab切换值
tabCheck(index) {
this.tabActive = index
this.tabActive = index;
},
// 由子组件触发,更改表达式组成的字段值
updateCrontabValue(name, value, from) {
"updateCrontabValue", name, value, from
this.crontabValueObj[name] = value
"updateCrontabValue", name, value, from;
this.crontabValueObj[name] = value;
if (from && from !== name) {
console.log(`来自组件 ${from} 改变了 ${name} ${value}`)
this.changeRadio(name, value)
console.log(`来自组件 ${from} 改变了 ${name} ${value}`);
this.changeRadio(name, value);
}
},
// 赋值到组件
changeRadio(name, value) {
let arr = ["second", "min", "hour", "month"],
refName = "cron" + name,
insValue
insValue;
if (!this.$refs[refName]) return
if (!this.$refs[refName]) return;
if (arr.includes(name)) {
if (value === "*") {
insValue = 1
insValue = 1;
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-")
let indexArr = value.split("-");
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0])
this.$refs[refName].cycle02 = indexArr[1]
insValue = 2
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insValue = 2;
} else if (value.indexOf("/") > -1) {
let indexArr = value.split("/")
let indexArr = value.split("/");
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 0)
: (this.$refs[refName].average01 = indexArr[0])
this.$refs[refName].average02 = indexArr[1]
insValue = 3
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insValue = 3;
} else {
insValue = 4
this.$refs[refName].checkboxList = value.split(",")
insValue = 4;
this.$refs[refName].checkboxList = value.split(",");
}
} else if (name == "day") {
if (value === "*") {
insValue = 1
insValue = 1;
} else if (value == "?") {
insValue = 2
insValue = 2;
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-")
let indexArr = value.split("-");
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0])
this.$refs[refName].cycle02 = indexArr[1]
insValue = 3
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insValue = 3;
} else if (value.indexOf("/") > -1) {
let indexArr = value.split("/")
let indexArr = value.split("/");
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 0)
: (this.$refs[refName].average01 = indexArr[0])
this.$refs[refName].average02 = indexArr[1]
insValue = 4
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insValue = 4;
} else if (value.indexOf("W") > -1) {
let indexArr = value.split("W")
let indexArr = value.split("W");
isNaN(indexArr[0])
? (this.$refs[refName].workday = 0)
: (this.$refs[refName].workday = indexArr[0])
insValue = 5
: (this.$refs[refName].workday = indexArr[0]);
insValue = 5;
} else if (value === "L") {
insValue = 6
insValue = 6;
} else {
this.$refs[refName].checkboxList = value.split(",")
insValue = 7
this.$refs[refName].checkboxList = value.split(",");
insValue = 7;
}
} else if (name == "week") {
if (value === "*") {
insValue = 1
insValue = 1;
} else if (value == "?") {
insValue = 2
insValue = 2;
} else if (value.indexOf("-") > -1) {
let indexArr = value.split("-")
let indexArr = value.split("-");
isNaN(indexArr[0])
? (this.$refs[refName].cycle01 = 0)
: (this.$refs[refName].cycle01 = indexArr[0])
this.$refs[refName].cycle02 = indexArr[1]
insValue = 3
: (this.$refs[refName].cycle01 = indexArr[0]);
this.$refs[refName].cycle02 = indexArr[1];
insValue = 3;
} else if (value.indexOf("#") > -1) {
let indexArr = value.split("#")
let indexArr = value.split("#");
isNaN(indexArr[0])
? (this.$refs[refName].average01 = 1)
: (this.$refs[refName].average01 = indexArr[0])
this.$refs[refName].average02 = indexArr[1]
insValue = 4
: (this.$refs[refName].average01 = indexArr[0]);
this.$refs[refName].average02 = indexArr[1];
insValue = 4;
} else if (value.indexOf("L") > -1) {
let indexArr = value.split("L")
let indexArr = value.split("L");
isNaN(indexArr[0])
? (this.$refs[refName].weekday = 1)
: (this.$refs[refName].weekday = indexArr[0])
insValue = 5
: (this.$refs[refName].weekday = indexArr[0]);
insValue = 5;
} else {
this.$refs[refName].checkboxList = value.split(",")
insValue = 6
this.$refs[refName].checkboxList = value.split(",");
insValue = 6;
}
} else if (name == "year") {
if (value == "") {
insValue = 1
insValue = 1;
} else if (value == "*") {
insValue = 2
insValue = 2;
} else if (value.indexOf("-") > -1) {
insValue = 3
insValue = 3;
} else if (value.indexOf("/") > -1) {
insValue = 4
insValue = 4;
} else {
this.$refs[refName].checkboxList = value.split(",")
insValue = 5
this.$refs[refName].checkboxList = value.split(",");
insValue = 5;
}
}
this.$refs[refName].radioValue = insValue
this.$refs[refName].radioValue = insValue;
},
// 表单选项的子组件校验数字格式(通过-props传递
checkNumber(value, minLimit, maxLimit) {
// 检查必须为整数
value = Math.floor(value)
value = Math.floor(value);
if (value < minLimit) {
value = minLimit
value = minLimit;
} else if (value > maxLimit) {
value = maxLimit
value = maxLimit;
}
return value
return value;
},
// 隐藏弹窗
hidePopup() {
this.$emit("hide")
this.$emit("hide");
},
// 填充表达式
submitFill() {
this.$emit("fill", this.crontabValueString)
this.hidePopup()
this.$emit("fill", this.crontabValueString);
this.hidePopup();
},
clearCron() {
// 还原选择项
("准备还原")
("准备还原");
this.crontabValueObj = {
second: "*",
min: "*",
@@ -322,15 +322,15 @@ export default {
month: "*",
week: "?",
year: "",
}
};
for (let j in this.crontabValueObj) {
this.changeRadio(j, this.crontabValueObj[j])
this.changeRadio(j, this.crontabValueObj[j]);
}
},
},
computed: {
crontabValueString: function() {
let obj = this.crontabValueObj
let obj = this.crontabValueObj;
let str =
obj.second +
" " +
@@ -343,8 +343,8 @@ export default {
obj.month +
" " +
obj.week +
(obj.year == "" ? "" : " " + obj.year)
return str
(obj.year == "" ? "" : " " + obj.year);
return str;
},
},
components: {
@@ -364,9 +364,9 @@ export default {
},
},
mounted: function() {
this.resolveExp()
this.resolveExp();
},
}
};
</script>
<style scoped>
.pop_btn {

View File

@@ -54,35 +54,35 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'min', '*', 'min')
break
this.$emit('update', 'min', '*', 'min');
break;
case 2:
this.$emit('update', 'min', this.cycleTotal, 'min')
break
this.$emit('update', 'min', this.cycleTotal, 'min');
break;
case 3:
this.$emit('update', 'min', this.averageTotal, 'min')
break
this.$emit('update', 'min', this.averageTotal, 'min');
break;
case 4:
this.$emit('update', 'min', this.checkboxString, 'min')
break
this.$emit('update', 'min', this.checkboxString, 'min');
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'min', this.cycleTotal, 'min')
this.$emit('update', 'min', this.cycleTotal, 'min');
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'min', this.averageTotal, 'min')
this.$emit('update', 'min', this.averageTotal, 'min');
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'min', this.checkboxString, 'min')
this.$emit('update', 'min', this.checkboxString, 'min');
}
},
@@ -98,18 +98,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 58)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
return cycle01 + '-' + cycle02
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 58)
const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
return average01 + '/' + average02
return average01 + '/' + average02;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str == '' ? '*' : str
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}

View File

@@ -53,35 +53,35 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'month', '*')
break
this.$emit('update', 'month', '*');
break;
case 2:
this.$emit('update', 'month', this.cycleTotal)
break
this.$emit('update', 'month', this.cycleTotal);
break;
case 3:
this.$emit('update', 'month', this.averageTotal)
break
this.$emit('update', 'month', this.averageTotal);
break;
case 4:
this.$emit('update', 'month', this.checkboxString)
break
this.$emit('update', 'month', this.checkboxString);
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'month', this.cycleTotal)
this.$emit('update', 'month', this.cycleTotal);
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'month', this.averageTotal)
this.$emit('update', 'month', this.averageTotal);
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'month', this.checkboxString)
this.$emit('update', 'month', this.checkboxString);
}
}
},
@@ -96,18 +96,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 1, 11)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
return cycle01 + '-' + cycle02
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 1, 11)
const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
return average01 + '/' + average02
return average01 + '/' + average02;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str == '' ? '*' : str
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}

View File

@@ -27,135 +27,135 @@ export default {
expressionChange() {
// 计算开始-隐藏结果
this.isShow = false
this.isShow = false;
// 获取规则数组[0秒、1分、2时、3日、4月、5星期、6年]
let ruleArr = this.$options.propsData.ex.split(' ')
let ruleArr = this.$options.propsData.ex.split(' ');
// 用于记录进入循环的次数
let nums = 0
let nums = 0;
// 用于暂时存符号时间规则结果的数组
let resultArr = []
let resultArr = [];
// 获取当前时间精确至[年、月、日、时、分、秒]
let nTime = new Date()
let nYear = nTime.getFullYear()
let nMonth = nTime.getMonth() + 1
let nDay = nTime.getDate()
let nHour = nTime.getHours()
let nMin = nTime.getMinutes()
let nSecond = nTime.getSeconds()
let nTime = new Date();
let nYear = nTime.getFullYear();
let nMonth = nTime.getMonth() + 1;
let nDay = nTime.getDate();
let nHour = nTime.getHours();
let nMin = nTime.getMinutes();
let nSecond = nTime.getSeconds();
// 根据规则获取到近100年可能年数组、月数组等等
this.getSecondArr(ruleArr[0])
this.getMinArr(ruleArr[1])
this.getHourArr(ruleArr[2])
this.getDayArr(ruleArr[3])
this.getMonthArr(ruleArr[4])
this.getWeekArr(ruleArr[5])
this.getYearArr(ruleArr[6], nYear)
this.getSecondArr(ruleArr[0]);
this.getMinArr(ruleArr[1]);
this.getHourArr(ruleArr[2]);
this.getDayArr(ruleArr[3]);
this.getMonthArr(ruleArr[4]);
this.getWeekArr(ruleArr[5]);
this.getYearArr(ruleArr[6], nYear);
// 将获取到的数组赋值-方便使用
let sDate = this.dateArr[0]
let mDate = this.dateArr[1]
let hDate = this.dateArr[2]
let DDate = this.dateArr[3]
let MDate = this.dateArr[4]
let YDate = this.dateArr[5]
let sDate = this.dateArr[0];
let mDate = this.dateArr[1];
let hDate = this.dateArr[2];
let DDate = this.dateArr[3];
let MDate = this.dateArr[4];
let YDate = this.dateArr[5];
// 获取当前时间在数组中的索引
let sIdx = this.getIndex(sDate, nSecond)
let mIdx = this.getIndex(mDate, nMin)
let hIdx = this.getIndex(hDate, nHour)
let DIdx = this.getIndex(DDate, nDay)
let MIdx = this.getIndex(MDate, nMonth)
let YIdx = this.getIndex(YDate, nYear)
let sIdx = this.getIndex(sDate, nSecond);
let mIdx = this.getIndex(mDate, nMin);
let hIdx = this.getIndex(hDate, nHour);
let DIdx = this.getIndex(DDate, nDay);
let MIdx = this.getIndex(MDate, nMonth);
let YIdx = this.getIndex(YDate, nYear);
// 重置月日时分秒的函数(后面用的比较多)
const resetSecond = function () {
sIdx = 0
sIdx = 0;
nSecond = sDate[sIdx]
}
const resetMin = function () {
mIdx = 0
mIdx = 0;
nMin = mDate[mIdx]
resetSecond()
resetSecond();
}
const resetHour = function () {
hIdx = 0
hIdx = 0;
nHour = hDate[hIdx]
resetMin()
resetMin();
}
const resetDay = function () {
DIdx = 0
DIdx = 0;
nDay = DDate[DIdx]
resetHour()
resetHour();
}
const resetMonth = function () {
MIdx = 0
MIdx = 0;
nMonth = MDate[MIdx]
resetDay()
resetDay();
}
// 如果当前年份不为数组中当前值
if (nYear !== YDate[YIdx]) {
resetMonth()
resetMonth();
}
// 如果当前月份不为数组中当前值
if (nMonth !== MDate[MIdx]) {
resetDay()
resetDay();
}
// 如果当前“日”不为数组中当前值
if (nDay !== DDate[DIdx]) {
resetHour()
resetHour();
}
// 如果当前“时”不为数组中当前值
if (nHour !== hDate[hIdx]) {
resetMin()
resetMin();
}
// 如果当前“分”不为数组中当前值
if (nMin !== mDate[mIdx]) {
resetSecond()
resetSecond();
}
// 循环年份数组
goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
let YY = YDate[Yi]
let YY = YDate[Yi];
// 如果到达最大值时
if (nMonth > MDate[MDate.length - 1]) {
resetMonth()
continue
resetMonth();
continue;
}
// 循环月份数组
goMonth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
// 赋值、方便后面运算
let MM = MDate[Mi];
MM = MM < 10 ? '0' + MM : MM
MM = MM < 10 ? '0' + MM : MM;
// 如果到达最大值时
if (nDay > DDate[DDate.length - 1]) {
resetDay()
resetDay();
if (Mi == MDate.length - 1) {
resetMonth()
continue goYear
resetMonth();
continue goYear;
}
continue
continue;
}
// 循环日期数组
goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
// 赋值、方便后面运算
let DD = DDate[Di]
let thisDD = DD < 10 ? '0' + DD : DD
let DD = DDate[Di];
let thisDD = DD < 10 ? '0' + DD : DD;
// 如果到达最大值时
if (nHour > hDate[hDate.length - 1]) {
resetHour()
resetHour();
if (Di == DDate.length - 1) {
resetDay()
resetDay();
if (Mi == MDate.length - 1) {
resetMonth()
continue goYear
resetMonth();
continue goYear;
}
continue goMonth
continue goMonth;
}
continue
continue;
}
// 判断日期的合法性,不合法的话也是跳出当前循环
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true && this.dayRule !== 'workDay' && this.dayRule !== 'lastWeek' && this.dayRule !== 'lastDay') {
resetDay()
continue goMonth
resetDay();
continue goMonth;
}
// 如果日期规则中有值时
if (this.dayRule == 'lastDay') {
@@ -163,83 +163,84 @@ export default {
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--
thisDD = DD < 10 ? '0' + DD : DD
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
}
}
} else if (this.dayRule == 'workDay') {
// 校验并调整如果是2月30号这种日期传进来时需调整至正常月底
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--
thisDD = DD < 10 ? '0' + DD : DD
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
}
}
// 获取达到条件的日期是星期X
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
// 当星期日时
if (thisWeek == 1) {
// 先找下一个日,并判断是否为月底
DD++
thisDD = DD < 10 ? '0' + DD : DD
DD++;
thisDD = DD < 10 ? '0' + DD : DD;
// 判断下一日已经不是合法日期
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD -= 3
DD -= 3;
}
} else if (thisWeek == 7) {
// 当星期6时只需判断不是1号就可进行操作
if (this.dayRuleSup !== 1) {
DD--
DD--;
} else {
DD += 2
DD += 2;
}
}
} else if (this.dayRule == 'weekDay') {
// 如果指定了是星期几
// 获取当前日期是属于星期几
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
// 校验当前星期是否在星期池dayRuleSup
if (this.dayRuleSup.indexOf(thisWeek) < 0) {
// 如果到达最大值时
if (Di == DDate.length - 1) {
resetDay()
resetDay();
if (Mi == MDate.length - 1) {
resetMonth()
continue goYear
resetMonth();
continue goYear;
}
continue goMonth
continue goMonth;
}
continue
continue;
}
} else if (this.dayRule == 'assWeek') {
// 如果指定了是第几周的星期几
// 获取每月1号是属于星期几
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week')
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
if (this.dayRuleSup[1] >= thisWeek) {
DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1
DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1;
} else {
DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1
DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1;
}
} else if (this.dayRule == 'lastWeek') {
// 如果指定了每月最后一个星期几
// 校验并调整如果是2月30号这种日期传进来时需调整至正常月底
if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
DD--
thisDD = DD < 10 ? '0' + DD : DD
DD--;
thisDD = DD < 10 ? '0' + DD : DD;
}
}
// 获取月末最后一天是星期几
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week')
let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
// 找到要求中最近的那个星期几
if (this.dayRuleSup < thisWeek) {
DD -= thisWeek - this.dayRuleSup
DD -= thisWeek - this.dayRuleSup;
} else if (this.dayRuleSup > thisWeek) {
DD -= 7 - (this.dayRuleSup - thisWeek)
}
}
// 判断时间值是否小于10置换成“05”这种格式
DD = DD < 10 ? '0' + DD : DD
DD = DD < 10 ? '0' + DD : DD;
// 循环“时”数组
goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
@@ -247,76 +248,76 @@ export default {
// 如果到达最大值时
if (nMin > mDate[mDate.length - 1]) {
resetMin()
resetMin();
if (hi == hDate.length - 1) {
resetHour()
resetHour();
if (Di == DDate.length - 1) {
resetDay()
resetDay();
if (Mi == MDate.length - 1) {
resetMonth()
continue goYear
resetMonth();
continue goYear;
}
continue goMonth
continue goMonth;
}
continue goDay
continue goDay;
}
continue
continue;
}
// 循环"分"数组
goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi]
let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi];
// 如果到达最大值时
if (nSecond > sDate[sDate.length - 1]) {
resetSecond()
resetSecond();
if (mi == mDate.length - 1) {
resetMin()
resetMin();
if (hi == hDate.length - 1) {
resetHour()
resetHour();
if (Di == DDate.length - 1) {
resetDay()
resetDay();
if (Mi == MDate.length - 1) {
resetMonth()
continue goYear
resetMonth();
continue goYear;
}
continue goMonth
continue goMonth;
}
continue goDay
continue goDay;
}
continue goHour
continue goHour;
}
continue
continue;
}
// 循环"秒"数组
goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si]
let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si];
// 添加当前时间(时间合法性在日期循环时已经判断)
if (MM !== '00' && DD !== '00') {
resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
nums++
nums++;
}
// 如果条数满了就退出循环
if (nums == 5) break goYear
if (nums == 5) break goYear;
// 如果到达最大值时
if (si == sDate.length - 1) {
resetSecond()
resetSecond();
if (mi == mDate.length - 1) {
resetMin()
resetMin();
if (hi == hDate.length - 1) {
resetHour()
resetHour();
if (Di == DDate.length - 1) {
resetDay()
resetDay();
if (Mi == MDate.length - 1) {
resetMonth()
continue goYear
resetMonth();
continue goYear;
}
continue goMonth
continue goMonth;
}
continue goDay
continue goDay;
}
continue goHour
continue goHour;
}
continue goMin
continue goMin;
}
} //goSecond
} //goMin
@@ -326,33 +327,33 @@ export default {
}
// 判断100年内的结果条数
if (resultArr.length == 0) {
this.resultList = ['没有达到条件的结果!']
this.resultList = ['没有达到条件的结果!'];
} else {
this.resultList = resultArr
this.resultList = resultArr;
if (resultArr.length !== 5) {
this.resultList.push('最近100年内只有上面' + resultArr.length + '条结果!')
}
}
// 计算完成-显示结果
this.isShow = true
this.isShow = true;
},
// 用于计算某位数字在数组中的索引
getIndex(arr, value) {
if (value <= arr[0] || value > arr[arr.length - 1]) {
return 0
return 0;
} else {
for (let i = 0; i < arr.length - 1; i++) {
if (value > arr[i] && value <= arr[i + 1]) {
return i + 1
return i + 1;
}
}
}
},
// 获取"年"数组
getYearArr(rule, year) {
this.dateArr[5] = this.getOrderArr(year, year + 100)
this.dateArr[5] = this.getOrderArr(year, year + 100);
if (rule !== undefined) {
if (rule.indexOf('-') >= 0) {
this.dateArr[5] = this.getCycleArr(rule, year + 100, false)
@@ -365,7 +366,7 @@ export default {
},
// 获取"月"数组
getMonthArr(rule) {
this.dateArr[4] = this.getOrderArr(1, 12)
this.dateArr[4] = this.getOrderArr(1, 12);
if (rule.indexOf('-') >= 0) {
this.dateArr[4] = this.getCycleArr(rule, 12, false)
} else if (rule.indexOf('/') >= 0) {
@@ -379,58 +380,58 @@ export default {
// 只有当日期规则的两个值均为“”时则表达日期是有选项的
if (this.dayRule == '' && this.dayRuleSup == '') {
if (rule.indexOf('-') >= 0) {
this.dayRule = 'weekDay'
this.dayRule = 'weekDay';
this.dayRuleSup = this.getCycleArr(rule, 7, false)
} else if (rule.indexOf('#') >= 0) {
this.dayRule = 'assWeek'
let matchRule = rule.match(/[0-9]{1}/g)
this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])]
this.dateArr[3] = [1]
this.dayRule = 'assWeek';
let matchRule = rule.match(/[0-9]{1}/g);
this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])];
this.dateArr[3] = [1];
if (this.dayRuleSup[1] == 7) {
this.dayRuleSup[1] = 0
this.dayRuleSup[1] = 0;
}
} else if (rule.indexOf('L') >= 0) {
this.dayRule = 'lastWeek'
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0])
this.dateArr[3] = [31]
this.dayRule = 'lastWeek';
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
this.dateArr[3] = [31];
if (this.dayRuleSup == 7) {
this.dayRuleSup = 0
this.dayRuleSup = 0;
}
} else if (rule !== '*' && rule !== '?') {
this.dayRule = 'weekDay'
this.dayRule = 'weekDay';
this.dayRuleSup = this.getAssignArr(rule)
}
}
},
// 获取"日"数组-少量为日期规则
getDayArr(rule) {
this.dateArr[3] = this.getOrderArr(1, 31)
this.dayRule = ''
this.dayRuleSup = ''
this.dateArr[3] = this.getOrderArr(1, 31);
this.dayRule = '';
this.dayRuleSup = '';
if (rule.indexOf('-') >= 0) {
this.dateArr[3] = this.getCycleArr(rule, 31, false)
this.dayRuleSup = 'null'
this.dayRuleSup = 'null';
} else if (rule.indexOf('/') >= 0) {
this.dateArr[3] = this.getAverageArr(rule, 31)
this.dayRuleSup = 'null'
this.dayRuleSup = 'null';
} else if (rule.indexOf('W') >= 0) {
this.dayRule = 'workDay'
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0])
this.dateArr[3] = [this.dayRuleSup]
this.dayRule = 'workDay';
this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
this.dateArr[3] = [this.dayRuleSup];
} else if (rule.indexOf('L') >= 0) {
this.dayRule = 'lastDay'
this.dayRuleSup = 'null'
this.dateArr[3] = [31]
this.dayRule = 'lastDay';
this.dayRuleSup = 'null';
this.dateArr[3] = [31];
} else if (rule !== '*' && rule !== '?') {
this.dateArr[3] = this.getAssignArr(rule)
this.dayRuleSup = 'null'
this.dayRuleSup = 'null';
} else if (rule == '*') {
this.dayRuleSup = 'null'
this.dayRuleSup = 'null';
}
},
// 获取"时"数组
getHourArr(rule) {
this.dateArr[2] = this.getOrderArr(0, 23)
this.dateArr[2] = this.getOrderArr(0, 23);
if (rule.indexOf('-') >= 0) {
this.dateArr[2] = this.getCycleArr(rule, 24, true)
} else if (rule.indexOf('/') >= 0) {
@@ -441,7 +442,7 @@ export default {
},
// 获取"分"数组
getMinArr(rule) {
this.dateArr[1] = this.getOrderArr(0, 59)
this.dateArr[1] = this.getOrderArr(0, 59);
if (rule.indexOf('-') >= 0) {
this.dateArr[1] = this.getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
@@ -452,7 +453,7 @@ export default {
},
// 获取"秒"数组
getSecondArr(rule) {
this.dateArr[0] = this.getOrderArr(0, 59)
this.dateArr[0] = this.getOrderArr(0, 59);
if (rule.indexOf('-') >= 0) {
this.dateArr[0] = this.getCycleArr(rule, 60, true)
} else if (rule.indexOf('/') >= 0) {
@@ -463,86 +464,86 @@ export default {
},
// 根据传进来的min-max返回一个顺序的数组
getOrderArr(min, max) {
let arr = []
let arr = [];
for (let i = min; i <= max; i++) {
arr.push(i)
arr.push(i);
}
return arr
return arr;
},
// 根据规则中指定的零散值返回一个数组
getAssignArr(rule) {
let arr = []
let assiginArr = rule.split(',')
let arr = [];
let assiginArr = rule.split(',');
for (let i = 0; i < assiginArr.length; i++) {
arr[i] = Number(assiginArr[i])
}
arr.sort(this.compare)
return arr
return arr;
},
// 根据一定算术规则计算返回一个数组
getAverageArr(rule, limit) {
let arr = []
let agArr = rule.split('/')
let min = Number(agArr[0])
let step = Number(agArr[1])
let arr = [];
let agArr = rule.split('/');
let min = Number(agArr[0]);
let step = Number(agArr[1]);
while (min <= limit) {
arr.push(min)
min += step
arr.push(min);
min += step;
}
return arr
return arr;
},
// 根据规则返回一个具有周期性的数组
getCycleArr(rule, limit, status) {
// status--表示是否从0开始则从1开始
let arr = []
let cycleArr = rule.split('-')
let min = Number(cycleArr[0])
let max = Number(cycleArr[1])
let arr = [];
let cycleArr = rule.split('-');
let min = Number(cycleArr[0]);
let max = Number(cycleArr[1]);
if (min > max) {
max += limit
max += limit;
}
for (let i = min; i <= max; i++) {
let add = 0
let add = 0;
if (status == false && i % limit == 0) {
add = limit
add = limit;
}
arr.push(Math.round(i % limit + add))
}
arr.sort(this.compare)
return arr
return arr;
},
// 比较数字大小用于Array.sort
compare(value1, value2) {
if (value2 - value1 > 0) {
return -1
return -1;
} else {
return 1
return 1;
}
},
// 格式化日期格式如2017-9-19 18:04:33
formatDate(value, type) {
// 计算日期相关值
let time = typeof value == 'number' ? new Date(value) : value
let Y = time.getFullYear()
let M = time.getMonth() + 1
let D = time.getDate()
let h = time.getHours()
let m = time.getMinutes()
let s = time.getSeconds()
let week = time.getDay()
let time = typeof value == 'number' ? new Date(value) : value;
let Y = time.getFullYear();
let M = time.getMonth() + 1;
let D = time.getDate();
let h = time.getHours();
let m = time.getMinutes();
let s = time.getSeconds();
let week = time.getDay();
// 如果传递了type的话
if (type == undefined) {
return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s)
return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
} else if (type == 'week') {
// 在quartz中 1为星期日
return week + 1
return week + 1;
}
},
// 检查日期是否存在
checkDate(value) {
let time = new Date(value)
let time = new Date(value);
let format = this.formatDate(time)
return value === format
return value === format;
}
},
watch: {
@@ -551,7 +552,7 @@ export default {
props: ['ex'],
mounted: function () {
// 初始化 获取一次结果
this.expressionChange()
this.expressionChange();
}
}

View File

@@ -53,35 +53,35 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'second', '*', 'second')
break
this.$emit('update', 'second', '*', 'second');
break;
case 2:
this.$emit('update', 'second', this.cycleTotal)
break
this.$emit('update', 'second', this.cycleTotal);
break;
case 3:
this.$emit('update', 'second', this.averageTotal)
break
this.$emit('update', 'second', this.averageTotal);
break;
case 4:
this.$emit('update', 'second', this.checkboxString)
break
this.$emit('update', 'second', this.checkboxString);
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '2') {
this.$emit('update', 'second', this.cycleTotal)
this.$emit('update', 'second', this.cycleTotal);
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '3') {
this.$emit('update', 'second', this.averageTotal)
this.$emit('update', 'second', this.averageTotal);
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '4') {
this.$emit('update', 'second', this.checkboxString)
this.$emit('update', 'second', this.checkboxString);
}
}
},
@@ -99,18 +99,18 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, 0, 58)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
return cycle01 + '-' + cycle02
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, 0, 58)
const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
return average01 + '/' + average02
return average01 + '/' + average02;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str == '' ? '*' : str
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}

View File

@@ -118,52 +118,52 @@ export default {
// 单选按钮值变化时
radioChange() {
if (this.radioValue !== 2 && this.cron.day !== '?') {
this.$emit('update', 'day', '?', 'week')
this.$emit('update', 'day', '?', 'week');
}
switch (this.radioValue) {
case 1:
this.$emit('update', 'week', '*')
break
this.$emit('update', 'week', '*');
break;
case 2:
this.$emit('update', 'week', '?')
break
this.$emit('update', 'week', '?');
break;
case 3:
this.$emit('update', 'week', this.cycleTotal)
break
this.$emit('update', 'week', this.cycleTotal);
break;
case 4:
this.$emit('update', 'week', this.averageTotal)
break
this.$emit('update', 'week', this.averageTotal);
break;
case 5:
this.$emit('update', 'week', this.weekdayCheck + 'L')
break
this.$emit('update', 'week', this.weekdayCheck + 'L');
break;
case 6:
this.$emit('update', 'week', this.checkboxString)
break
this.$emit('update', 'week', this.checkboxString);
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'week', this.cycleTotal)
this.$emit('update', 'week', this.cycleTotal);
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'week', this.averageTotal)
this.$emit('update', 'week', this.averageTotal);
}
},
// 最近工作日值变化时
weekdayChange() {
if (this.radioValue == '5') {
this.$emit('update', 'week', this.weekday + 'L')
this.$emit('update', 'week', this.weekday + 'L');
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '6') {
this.$emit('update', 'week', this.checkboxString)
this.$emit('update', 'week', this.checkboxString);
}
},
},
@@ -179,23 +179,23 @@ export default {
cycleTotal: function () {
this.cycle01 = this.checkNum(this.cycle01, 1, 7)
this.cycle02 = this.checkNum(this.cycle02, 1, 7)
return this.cycle01 + '-' + this.cycle02
return this.cycle01 + '-' + this.cycle02;
},
// 计算平均用到的值
averageTotal: function () {
this.average01 = this.checkNum(this.average01, 1, 4)
this.average02 = this.checkNum(this.average02, 1, 7)
return this.average02 + '#' + this.average01
return this.average02 + '#' + this.average01;
},
// 最近的工作日(格式)
weekdayCheck: function () {
this.weekday = this.checkNum(this.weekday, 1, 7)
return this.weekday
return this.weekday;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str == '' ? '*' : str
let str = this.checkboxList.join();
return str == '' ? '*' : str;
}
}
}

View File

@@ -61,38 +61,38 @@ export default {
radioChange() {
switch (this.radioValue) {
case 1:
this.$emit('update', 'year', '')
break
this.$emit('update', 'year', '');
break;
case 2:
this.$emit('update', 'year', '*')
break
this.$emit('update', 'year', '*');
break;
case 3:
this.$emit('update', 'year', this.cycleTotal)
break
this.$emit('update', 'year', this.cycleTotal);
break;
case 4:
this.$emit('update', 'year', this.averageTotal)
break
this.$emit('update', 'year', this.averageTotal);
break;
case 5:
this.$emit('update', 'year', this.checkboxString)
break
this.$emit('update', 'year', this.checkboxString);
break;
}
},
// 周期两个值变化时
cycleChange() {
if (this.radioValue == '3') {
this.$emit('update', 'year', this.cycleTotal)
this.$emit('update', 'year', this.cycleTotal);
}
},
// 平均两个值变化时
averageChange() {
if (this.radioValue == '4') {
this.$emit('update', 'year', this.averageTotal)
this.$emit('update', 'year', this.averageTotal);
}
},
// checkbox值变化时
checkboxChange() {
if (this.radioValue == '5') {
this.$emit('update', 'year', this.checkboxString)
this.$emit('update', 'year', this.checkboxString);
}
}
},
@@ -107,23 +107,23 @@ export default {
cycleTotal: function () {
const cycle01 = this.checkNum(this.cycle01, this.fullYear, 2098)
const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : this.fullYear + 1, 2099)
return cycle01 + '-' + cycle02
return cycle01 + '-' + cycle02;
},
// 计算平均用到的值
averageTotal: function () {
const average01 = this.checkNum(this.average01, this.fullYear, 2098)
const average02 = this.checkNum(this.average02, 1, 2099 - average01 || this.fullYear)
return average01 + '/' + average02
return average01 + '/' + average02;
},
// 计算勾选的checkbox值合集
checkboxString: function () {
let str = this.checkboxList.join()
return str
let str = this.checkboxList.join();
return str;
}
},
mounted: function () {
// 仅获取当前年份
this.fullYear = Number(new Date().getFullYear())
this.fullYear = Number(new Date().getFullYear());
this.cycle01 = this.fullYear
this.average01 = this.fullYear
}

Some files were not shown because too many files have changed in this diff Show More