😴发布 4.8.2 正式进入维护状态

This commit is contained in:
疯狂的狮子Li 2023-11-27 13:23:41 +08:00
parent a6f62ca86f
commit 267ff79b0c
53 changed files with 398 additions and 288 deletions

View File

@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> <configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile"> <deployment type="dockerfile">
<settings> <settings>
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.8.1" /> <option name="imageTag" value="ruoyi/ruoyi-monitor-admin:4.8.2" />
<option name="buildOnly" value="true" /> <option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" /> <option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
</settings> </settings>

View File

@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> <configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile"> <deployment type="dockerfile">
<settings> <settings>
<option name="imageTag" value="ruoyi/ruoyi-server:4.8.1" /> <option name="imageTag" value="ruoyi/ruoyi-server:4.8.2" />
<option name="buildOnly" value="true" /> <option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" /> <option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
</settings> </settings>

View File

@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-xxl-job-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker"> <configuration default="false" name="ruoyi-xxl-job-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile"> <deployment type="dockerfile">
<settings> <settings>
<option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.8.1" /> <option name="imageTag" value="ruoyi/ruoyi-xxl-job-admin:4.8.2" />
<option name="buildOnly" value="true" /> <option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" /> <option name="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" />
</settings> </settings>

View File

@ -3,6 +3,14 @@
- - - - - -
## 版本状态说明
由于 springboot 2.X 与 vue 2.X 官方均宣布停止维护, 故而 框架 4.X 版本 进入维护状态(只处理问题不更新功能)
停止维护时间预计: 2024年6-10月具体根据使用人数动态决定, 此版本已经相当稳定 即便不更新功能也不影响使用
如果依旧选择使用 jdk8 或者 jdk11 可以放心使用此版本, 如果希望使用 jdk17 或者 jdk21 可以选择使用 5.X 分支
## 平台简介 ## 平台简介
[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus) [![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus)
@ -10,7 +18,7 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) [![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br> <br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.8.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) [![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-4.8.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg)]() [![Spring Boot](https://img.shields.io/badge/Spring%20Boot-2.7-blue.svg)]()
[![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]() [![JDK-8+](https://img.shields.io/badge/JDK-8-green.svg)]()
[![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]() [![JDK-11](https://img.shields.io/badge/JDK-11-green.svg)]()

28
pom.xml
View File

@ -6,15 +6,15 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<version>4.8.1</version> <version>4.8.2</version>
<name>RuoYi-Vue-Plus</name> <name>RuoYi-Vue-Plus</name>
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url> <url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
<description>RuoYi-Vue-Plus后台管理系统</description> <description>RuoYi-Vue-Plus后台管理系统</description>
<properties> <properties>
<ruoyi-vue-plus.version>4.8.1</ruoyi-vue-plus.version> <ruoyi-vue-plus.version>4.8.2</ruoyi-vue-plus.version>
<spring-boot.version>2.7.16</spring-boot.version> <spring-boot.version>2.7.18</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
@ -24,10 +24,10 @@
<poi.version>5.2.3</poi.version> <poi.version>5.2.3</poi.version>
<easyexcel.version>3.3.2</easyexcel.version> <easyexcel.version>3.3.2</easyexcel.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<satoken.version>1.36.0</satoken.version> <satoken.version>1.37.0</satoken.version>
<mybatis-plus.version>3.5.3.2</mybatis-plus.version> <mybatis-plus.version>3.5.4</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version> <p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.20</hutool.version> <hutool.version>5.8.22</hutool.version>
<okhttp.version>4.10.0</okhttp.version> <okhttp.version>4.10.0</okhttp.version>
<spring-boot-admin.version>2.7.11</spring-boot-admin.version> <spring-boot-admin.version>2.7.11</spring-boot-admin.version>
<redisson.version>3.20.1</redisson.version> <redisson.version>3.20.1</redisson.version>
@ -40,11 +40,8 @@
<!-- 离线IP地址定位库 --> <!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version> <ip2region.version>2.7.0</ip2region.version>
<!-- 临时修复 snakeyaml 漏洞 -->
<snakeyaml.version>1.33</snakeyaml.version>
<!-- OSS 配置 --> <!-- OSS 配置 -->
<aws-java-sdk-s3.version>1.12.400</aws-java-sdk-s3.version> <aws-java-sdk-s3.version>1.12.540</aws-java-sdk-s3.version>
<!-- SMS 配置 --> <!-- SMS 配置 -->
<sms4j.version>2.2.0</sms4j.version> <sms4j.version>2.2.0</sms4j.version>
</properties> </properties>
@ -55,7 +52,7 @@
<properties> <properties>
<!-- 环境标识,需要与配置文件的名称相对应 --> <!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active> <profiles.active>local</profiles.active>
<logging.level>debug</logging.level> <logging.level>info</logging.level>
</properties> </properties>
</profile> </profile>
<profile> <profile>
@ -63,7 +60,7 @@
<properties> <properties>
<!-- 环境标识,需要与配置文件的名称相对应 --> <!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active> <profiles.active>dev</profiles.active>
<logging.level>debug</logging.level> <logging.level>info</logging.level>
</properties> </properties>
<activation> <activation>
<!-- 默认环境 --> <!-- 默认环境 -->
@ -261,13 +258,6 @@
<version>${ip2region.version}</version> <version>${ip2region.version}</version>
</dependency> </dependency>
<!-- 临时修复 snakeyaml 漏洞 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<!-- 加密包引入 --> <!-- 加密包引入 -->
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.8.1</version> <version>4.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-extend</artifactId> <artifactId>ruoyi-extend</artifactId>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-extend</artifactId> <artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.8.1</version> <version>4.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ruoyi-extend</artifactId> <artifactId>ruoyi-extend</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.8.1</version> <version>4.8.2</version>
</parent> </parent>
<artifactId>ruoyi-xxl-job-admin</artifactId> <artifactId>ruoyi-xxl-job-admin</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,6 +1,6 @@
{ {
"name": "ruoyi-vue-plus", "name": "ruoyi-vue-plus",
"version": "4.8.1", "version": "4.8.2",
"description": "RuoYi-Vue-Plus后台管理系统", "description": "RuoYi-Vue-Plus后台管理系统",
"author": "LionLi", "author": "LionLi",
"license": "MIT", "license": "MIT",
@ -15,7 +15,7 @@
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.0.10", "@element-plus/icons-vue": "2.0.10",
"@vueup/vue-quill": "1.1.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "9.5.0", "@vueuse/core": "9.5.0",
"axios": "0.27.2", "axios": "0.27.2",
"echarts": "5.4.0", "echarts": "5.4.0",

View File

@ -9,14 +9,13 @@
name="file" name="file"
:show-file-list="false" :show-file-list="false"
:headers="headers" :headers="headers"
style="display: none"
ref="uploadRef" ref="uploadRef"
v-if="type == 'url'" v-if="type == 'url'"
> >
</el-upload> </el-upload>
<div class="editor"> <div class="editor">
<quill-editor <quill-editor
ref="myQuillEditor" ref="quillEditorRef"
v-model:content="content" v-model:content="content"
contentType="html" contentType="html"
@textChange="(e) => $emit('update:modelValue', content)" @textChange="(e) => $emit('update:modelValue', content)"
@ -68,7 +67,7 @@ const { proxy } = getCurrentInstance();
// //
const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/system/oss/upload"); const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/system/oss/upload");
const headers = ref({ Authorization: "Bearer " + getToken() }); const headers = ref({ Authorization: "Bearer " + getToken() });
const myQuillEditor = ref(); const quillEditorRef = ref();
const options = ref({ const options = ref({
theme: "snow", theme: "snow",
@ -101,7 +100,7 @@ const options = ref({
}, },
} }
}, },
placeholder: '请输入内容', placeholder: "请输入内容",
readOnly: props.readOnly, readOnly: props.readOnly,
}); });
@ -114,7 +113,7 @@ const styles = computed(() => {
style.height = `${props.height}px`; style.height = `${props.height}px`;
} }
return style; return style;
}) });
const content = ref(""); const content = ref("");
watch(() => props.modelValue, (v) => { watch(() => props.modelValue, (v) => {
@ -125,10 +124,10 @@ watch(() => props.modelValue, (v) => {
// //
function handleUploadSuccess(res, file) { function handleUploadSuccess(res, file) {
//
let quill = toRaw(myQuillEditor.value).getQuill();
// //
if (res.code == 200) { if (res.code == 200) {
//
let quill = toRaw(quillEditorRef.value).getQuill();
// //
let length = quill.selection.savedRange.index; let length = quill.selection.savedRange.index;
// res // res
@ -144,6 +143,13 @@ function handleUploadSuccess(res, file) {
// //
function handleBeforeUpload(file) { function handleBeforeUpload(file) {
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
const isJPG = type.includes(file.type);
//
if (!isJPG) {
proxy.$modal.msgError(`图片格式错误!`);
return false;
}
// //
if (props.fileSize) { if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize; const isLt = file.size / 1024 / 1024 < props.fileSize;
@ -164,6 +170,9 @@ function handleUploadError(err) {
</script> </script>
<style> <style>
.editor-img-uploader {
display: none;
}
.editor, .ql-toolbar { .editor, .ql-toolbar {
white-space: pre-wrap !important; white-space: pre-wrap !important;
line-height: normal !important; line-height: normal !important;

View File

@ -45,12 +45,17 @@ function close() {
} }
function change(val) { function change(val) {
const path = val.path; const path = val.path;
const query = val.query;
if (isHttp(path)) { if (isHttp(path)) {
// http(s):// // http(s)://
const pindex = path.indexOf("http"); const pindex = path.indexOf("http");
window.open(path.substr(pindex, path.length), "_blank"); window.open(path.substr(pindex, path.length), "_blank");
} else { } else {
router.push(path) if (query) {
router.push({ path: path, query: JSON.parse(query) });
} else {
router.push(path)
}
} }
search.value = '' search.value = ''
@ -77,7 +82,7 @@ function initFuse(list) {
} }
// Filter out the routes that can be displayed in the sidebar // Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title // And generate the internationalized title
function generateRoutes(routes, basePath = '', prefixTitle = []) { function generateRoutes(routes, basePath = '', prefixTitle = [], query = {}) {
let res = [] let res = []
for (const r of routes) { for (const r of routes) {
@ -99,9 +104,13 @@ function generateRoutes(routes, basePath = '', prefixTitle = []) {
} }
} }
if (r.query) {
data.query = r.query
}
// recursive child routes // recursive child routes
if (r.children) { if (r.children) {
const tempRoutes = generateRoutes(r.children, data.path, data.title) const tempRoutes = generateRoutes(r.children, data.path, data.title, data.query)
if (tempRoutes.length >= 1) { if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes] res = [...res, ...tempRoutes]
} }
@ -176,4 +185,4 @@ watch(searchPool, (list) => {
} }
} }
} }
</style> </style>

View File

@ -5,15 +5,23 @@
:key="item.path" :key="item.path"
:iframeId="'iframe' + index" :iframeId="'iframe' + index"
v-show="route.path === item.path" v-show="route.path === item.path"
:src="item.meta.link" :src="iframeUrl(item.meta.link, item.query)"
></inner-link> ></inner-link>
</transition-group> </transition-group>
</template> </template>
<script setup> <script setup>
import InnerLink from "../InnerLink/index" import InnerLink from "../InnerLink/index";
import useTagsViewStore from '@/store/modules/tagsView' import useTagsViewStore from "@/store/modules/tagsView";
const route = useRoute(); const route = useRoute();
const tagsViewStore = useTagsViewStore() const tagsViewStore = useTagsViewStore();
function iframeUrl(url, query) {
if (Object.keys(query).length > 0) {
let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
return url + "?" + params;
}
return url;
}
</script> </script>

View File

@ -101,6 +101,10 @@ function filterChildren(childrenMap, lastRouter = false) {
} }
if (lastRouter) { if (lastRouter) {
el.path = lastRouter.path + '/' + el.path el.path = lastRouter.path + '/' + el.path
if (el.children && el.children.length) {
children = children.concat(filterChildren(el.children, el))
return
}
} }
children = children.concat(el) children = children.concat(el)
}) })

View File

@ -7,6 +7,7 @@ const useUserStore = defineStore(
{ {
state: () => ({ state: () => ({
token: getToken(), token: getToken(),
id: '',
name: '', name: '',
avatar: '', avatar: '',
roles: [], roles: [],
@ -42,8 +43,9 @@ const useUserStore = defineStore(
} else { } else {
this.roles = ['ROLE_DEFAULT'] this.roles = ['ROLE_DEFAULT']
} }
this.id = user.userId
this.name = user.userName this.name = user.userName
this.avatar = avatar; this.avatar = avatar
resolve(res) resolve(res)
}).catch(error => { }).catch(error => {
reject(error) reject(error)

View File

@ -336,7 +336,7 @@ function submitForm() {
proxy.$refs["demoRef"].validate(valid => { proxy.$refs["demoRef"].validate(valid => {
if (valid) { if (valid) {
buttonLoading.value = true; buttonLoading.value = true;
if (form.value.ossConfigId != null) { if (form.value.id != null) {
updateDemo(form.value).then(response => { updateDemo(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功"); proxy.$modal.msgSuccess("修改成功");
open.value = false; open.value = false;

View File

@ -243,7 +243,7 @@ function submitForm() {
proxy.$refs["treeRef"].validate(valid => { proxy.$refs["treeRef"].validate(valid => {
if (valid) { if (valid) {
buttonLoading.value = true; buttonLoading.value = true;
if (form.value.ossConfigId != null) { if (form.value.id != null) {
updateTree(form.value).then(response => { updateTree(form.value).then(response => {
proxy.$modal.msgSuccess("修改成功"); proxy.$modal.msgSuccess("修改成功");
open.value = false; open.value = false;

View File

@ -103,7 +103,7 @@
</template> </template>
<script setup name="Index"> <script setup name="Index">
const version = ref('4.8.1') const version = ref('4.8.2')
function goTarget(url) { function goTarget(url) {
window.open(url, '__blank') window.open(url, '__blank')

View File

@ -1,7 +1,16 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="系统模块" prop="title"> <el-form-item label="操作地址" prop="operIp">
<el-input
v-model="queryParams.operIp"
placeholder="请输入操作地址"
clearable
style="width: 240px;"
@keyup.enter="handleQuery"
/>
</el-form-item>
<el-form-item label="系统模块" prop="title">
<el-input <el-input
v-model="queryParams.title" v-model="queryParams.title"
placeholder="请输入系统模块" placeholder="请输入系统模块"
@ -107,9 +116,12 @@
<dict-tag :options="sys_oper_type" :value="scope.row.businessType" /> <dict-tag :options="sys_oper_type" :value="scope.row.businessType" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="请求方式" align="center" prop="requestMethod" />
<el-table-column label="操作人员" align="center" width="110" prop="operName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" /> <el-table-column label="操作人员" align="center" width="110" prop="operName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" /> <el-table-column label="部门" align="center" prop="deptName" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status"> <el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status">
<template #default="scope"> <template #default="scope">
<dict-tag :options="sys_common_status" :value="scope.row.status" /> <dict-tag :options="sys_common_status" :value="scope.row.status" />
</template> </template>
@ -143,15 +155,16 @@
<el-dialog title="操作日志详细" v-model="open" width="700px" append-to-body> <el-dialog title="操作日志详细" v-model="open" width="700px" append-to-body>
<el-form :model="form" label-width="100px"> <el-form :model="form" label-width="100px">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="24">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
<el-form-item <el-form-item
label="登录信息:" label="登录信息:"
>{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item> >{{ form.operName }} / {{form.deptName}} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item> <el-form-item label="请求信息:">{{ form.requestMethod }} {{form.operUrl }}</el-form-item>
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item> </el-col>
<el-col :span="12">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="操作方法:">{{ form.method }}</el-form-item> <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
@ -211,6 +224,7 @@ const data = reactive({
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
operIp: undefined,
title: undefined, title: undefined,
operName: undefined, operName: undefined,
businessType: undefined, businessType: undefined,

View File

@ -246,7 +246,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12" v-if="form.menuType != 'F'"> <el-col :span="12">
<el-form-item> <el-form-item>
<template #label> <template #label>
<span> <span>

View File

@ -149,7 +149,7 @@
<el-form-item prop="roleKey"> <el-form-item prop="roleKey">
<template #label> <template #label>
<span> <span>
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top"> <el-tooltip content="控制器中定义的权限字符,如:@SaCheckRole('admin')" placement="top">
<el-icon><question-filled /></el-icon> <el-icon><question-filled /></el-icon>
</el-tooltip> </el-tooltip>
权限字符 权限字符

View File

@ -605,4 +605,7 @@ function submitForm() {
getDeptTree(); getDeptTree();
getList(); getList();
proxy.getConfigKey("sys.user.initPassword").then(response => {
initPassword.value = response.msg;
});
</script> </script>

View File

@ -1,6 +1,6 @@
{ {
"name": "ruoyi-vue-plus", "name": "ruoyi-vue-plus",
"version": "4.8.1", "version": "4.8.2",
"description": "RuoYi-Vue-Plus后台管理系统", "description": "RuoYi-Vue-Plus后台管理系统",
"author": "LionLi", "author": "LionLi",
"license": "MIT", "license": "MIT",

View File

@ -47,7 +47,7 @@ export default {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
// (MB) /* 上传文件大小限制(MB) */
fileSize: { fileSize: {
type: Number, type: Number,
default: 5, default: 5,
@ -129,7 +129,6 @@ export default {
if (this.type == 'url') { if (this.type == 'url') {
let toolbar = this.Quill.getModule("toolbar"); let toolbar = this.Quill.getModule("toolbar");
toolbar.addHandler("image", (value) => { toolbar.addHandler("image", (value) => {
this.uploadType = "image";
if (value) { if (value) {
this.$refs.upload.$children[0].$refs.input.click(); this.$refs.upload.$children[0].$refs.input.click();
} else { } else {
@ -158,6 +157,13 @@ export default {
}, },
// //
handleBeforeUpload(file) { handleBeforeUpload(file) {
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
const isJPG = type.includes(file.type);
//
if (!isJPG) {
this.$message.error(`图片格式错误!`);
return false;
}
// //
if (this.fileSize) { if (this.fileSize) {
const isLt = file.size / 1024 / 1024 < this.fileSize; const isLt = file.size / 1024 / 1024 < this.fileSize;
@ -169,10 +175,10 @@ export default {
return true; return true;
}, },
handleUploadSuccess(res, file) { handleUploadSuccess(res, file) {
//
let quill = this.Quill;
// //
if (res.code == 200) { if (res.code == 200) {
//
let quill = this.Quill;
// //
let length = quill.getSelection().index; let length = quill.getSelection().index;
// res.url // res.url

View File

@ -71,12 +71,17 @@ export default {
}, },
change(val) { change(val) {
const path = val.path; const path = val.path;
const query = val.query;
if(this.ishttp(val.path)) { if(this.ishttp(val.path)) {
// http(s):// // http(s)://
const pindex = path.indexOf("http"); const pindex = path.indexOf("http");
window.open(path.substr(pindex, path.length), "_blank"); window.open(path.substr(pindex, path.length), "_blank");
} else { } else {
this.$router.push(val.path) if (query) {
this.$router.push({ path: path, query: JSON.parse(query) });
} else {
this.$router.push(path)
}
} }
this.search = '' this.search = ''
this.options = [] this.options = []
@ -102,7 +107,7 @@ export default {
}, },
// Filter out the routes that can be displayed in the sidebar // Filter out the routes that can be displayed in the sidebar
// And generate the internationalized title // And generate the internationalized title
generateRoutes(routes, basePath = '/', prefixTitle = []) { generateRoutes(routes, basePath = '/', prefixTitle = [], query = {}) {
let res = [] let res = []
for (const router of routes) { for (const router of routes) {
@ -124,9 +129,13 @@ export default {
} }
} }
if (router.query) {
data.query = router.query
}
// recursive child routes // recursive child routes
if (router.children) { if (router.children) {
const tempRoutes = this.generateRoutes(router.children, data.path, data.title) const tempRoutes = this.generateRoutes(router.children, data.path, data.title, data.query)
if (tempRoutes.length >= 1) { if (tempRoutes.length >= 1) {
res = [...res, ...tempRoutes] res = [...res, ...tempRoutes]
} }

View File

@ -5,19 +5,28 @@
:key="item.path" :key="item.path"
:iframeId="'iframe' + index" :iframeId="'iframe' + index"
v-show="$route.path === item.path" v-show="$route.path === item.path"
:src="item.meta.link" :src="iframeUrl(item.meta.link, item.query)"
></inner-link> ></inner-link>
</transition-group> </transition-group>
</template> </template>
<script> <script>
import InnerLink from "../InnerLink/index" import InnerLink from "../InnerLink/index";
export default { export default {
components: { InnerLink }, components: { InnerLink },
computed: { computed: {
iframeViews() { iframeViews() {
return this.$store.state.tagsView.iframeViews return this.$store.state.tagsView.iframeViews;
}
},
methods: {
iframeUrl(url, query) {
if (Object.keys(query).length > 0) {
let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
return url + "?" + params;
}
return url;
} }
} }
} }

View File

@ -98,6 +98,10 @@ function filterChildren(childrenMap, lastRouter = false) {
} }
if (lastRouter) { if (lastRouter) {
el.path = lastRouter.path + '/' + el.path el.path = lastRouter.path + '/' + el.path
if (el.children && el.children.length) {
children = children.concat(filterChildren(el.children, el))
return
}
} }
children = children.concat(el) children = children.concat(el)
}) })

View File

@ -4,6 +4,7 @@ import { getToken, setToken, removeToken } from '@/utils/auth'
const user = { const user = {
state: { state: {
token: getToken(), token: getToken(),
id: '',
name: '', name: '',
avatar: '', avatar: '',
roles: [], roles: [],
@ -14,6 +15,9 @@ const user = {
SET_TOKEN: (state, token) => { SET_TOKEN: (state, token) => {
state.token = token state.token = token
}, },
SET_ID: (state, id) => {
state.id = id
},
SET_NAME: (state, name) => { SET_NAME: (state, name) => {
state.name = name state.name = name
}, },
@ -58,6 +62,7 @@ const user = {
} else { } else {
commit('SET_ROLES', ['ROLE_DEFAULT']) commit('SET_ROLES', ['ROLE_DEFAULT'])
} }
commit('SET_ID', user.userId)
commit('SET_NAME', user.userName) commit('SET_NAME', user.userName)
commit('SET_AVATAR', avatar) commit('SET_AVATAR', avatar)
resolve(res) resolve(res)

View File

@ -114,7 +114,7 @@ export default {
data() { data() {
return { return {
// //
version: "4.8.1", version: "4.8.2",
}; };
}, },
methods: { methods: {

View File

@ -1,148 +1,148 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-row> <el-row>
<el-col :span="24" class="card-box"> <el-col :span="24" class="card-box">
<el-card> <el-card>
<div slot="header"><span><i class="el-icon-monitor"></i> 基本信息</span></div> <div slot="header"><span><i class="el-icon-monitor"></i> 基本信息</span></div>
<div class="el-table el-table--enable-row-hover el-table--medium"> <div class="el-table el-table--enable-row-hover el-table--medium">
<table cellspacing="0" style="width: 100%"> <table cellspacing="0" style="width: 100%">
<tbody> <tbody>
<tr> <tr>
<td class="el-table__cell is-leaf"><div class="cell">Redis版本</div></td> <td class="el-table__cell is-leaf"><div class="cell">Redis版本</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">运行模式</div></td> <td class="el-table__cell is-leaf"><div class="cell">运行模式</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">端口</div></td> <td class="el-table__cell is-leaf"><div class="cell">端口</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">客户端数</div></td> <td class="el-table__cell is-leaf"><div class="cell">客户端数</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
</tr> </tr>
<tr> <tr>
<td class="el-table__cell is-leaf"><div class="cell">运行时间()</div></td> <td class="el-table__cell is-leaf"><div class="cell">运行时间()</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">使用内存</div></td> <td class="el-table__cell is-leaf"><div class="cell">使用内存</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">使用CPU</div></td> <td class="el-table__cell is-leaf"><div class="cell">使用CPU</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">内存配置</div></td> <td class="el-table__cell is-leaf"><div class="cell">内存配置</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
</tr> </tr>
<tr> <tr>
<td class="el-table__cell is-leaf"><div class="cell">AOF是否开启</div></td> <td class="el-table__cell is-leaf"><div class="cell">AOF是否开启</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">RDB是否成功</div></td> <td class="el-table__cell is-leaf"><div class="cell">RDB是否成功</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
<td class="el-table__cell is-leaf"><div class="cell">Key数量</div></td> <td class="el-table__cell is-leaf"><div class="cell">Key数量</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
<td class="el-table__cell is-leaf"><div class="cell">网络入口/出口</div></td> <td class="el-table__cell is-leaf"><div class="cell">网络入口/出口</div></td>
<td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td> <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="12" class="card-box"> <el-col :span="12" class="card-box">
<el-card> <el-card>
<div slot="header"><span><i class="el-icon-pie-chart"></i> 命令统计</span></div> <div slot="header"><span><i class="el-icon-pie-chart"></i> 命令统计</span></div>
<div class="el-table el-table--enable-row-hover el-table--medium"> <div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="commandstats" style="height: 420px" /> <div ref="commandstats" style="height: 420px" />
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="12" class="card-box"> <el-col :span="12" class="card-box">
<el-card> <el-card>
<div slot="header"><span><i class="el-icon-odometer"></i> 内存信息</span></div> <div slot="header"><span><i class="el-icon-odometer"></i> 内存信息</span></div>
<div class="el-table el-table--enable-row-hover el-table--medium"> <div class="el-table el-table--enable-row-hover el-table--medium">
<div ref="usedmemory" style="height: 420px" /> <div ref="usedmemory" style="height: 420px" />
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script> <script>
import { getCache } from "@/api/monitor/cache"; import { getCache } from "@/api/monitor/cache";
import * as echarts from "echarts"; import * as echarts from "echarts";
export default { export default {
name: "Cache", name: "Cache",
data() { data() {
return { return {
// //
commandstats: null, commandstats: null,
// 使 // 使
usedmemory: null, usedmemory: null,
// cache // cache
cache: [] cache: []
} }
}, },
created() { created() {
this.getList(); this.getList();
this.openLoading(); this.openLoading();
}, },
methods: { methods: {
/** 查缓存询信息 */ /** 查缓存询信息 */
getList() { getList() {
getCache().then((response) => { getCache().then((response) => {
this.cache = response.data; this.cache = response.data;
this.$modal.closeLoading(); this.$modal.closeLoading();
this.commandstats = echarts.init(this.$refs.commandstats, "macarons"); this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
this.commandstats.setOption({ this.commandstats.setOption({
tooltip: { tooltip: {
trigger: "item", trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)", formatter: "{a} <br/>{b} : {c} ({d}%)",
}, },
series: [ series: [
{ {
name: "命令", name: "命令",
type: "pie", type: "pie",
roseType: "radius", roseType: "radius",
radius: [15, 95], radius: [15, 95],
center: ["50%", "38%"], center: ["50%", "38%"],
data: response.data.commandStats, data: response.data.commandStats,
animationEasing: "cubicInOut", animationEasing: "cubicInOut",
animationDuration: 1000, animationDuration: 1000,
} }
] ]
}); });
this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons"); this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
this.usedmemory.setOption({ this.usedmemory.setOption({
tooltip: { tooltip: {
formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human, formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
}, },
series: [ series: [
{ {
name: "峰值", name: "峰值",
type: "gauge", type: "gauge",
min: 0, min: 0,
max: 1000, max: 1000,
detail: { detail: {
formatter: this.cache.info.used_memory_human, formatter: this.cache.info.used_memory_human,
}, },
data: [ data: [
{ {
value: parseFloat(this.cache.info.used_memory_human), value: parseFloat(this.cache.info.used_memory_human),
name: "内存消耗", name: "内存消耗",
} }
] ]
} }
] ]
}); });
window.addEventListener("resize",()=>{ window.addEventListener("resize",()=>{
this.commandstats.resize() this.commandstats.resize()
this.usedmemory.resize() this.usedmemory.resize()
}); });
}); });
}, },
// //
openLoading() { openLoading() {
this.$modal.loading("正在加载缓存监控数据,请稍候!"); this.$modal.loading("正在加载缓存监控数据,请稍候!");
} }
} }
}; };
</script> </script>

View File

@ -1,6 +1,15 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="操作地址" prop="operIp">
<el-input
v-model="queryParams.operIp"
placeholder="请输入操作地址"
clearable
style="width: 240px;"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="系统模块" prop="title"> <el-form-item label="系统模块" prop="title">
<el-input <el-input
v-model="queryParams.title" v-model="queryParams.title"
@ -113,6 +122,7 @@
</el-table-column> </el-table-column>
<el-table-column label="请求方式" align="center" prop="requestMethod" /> <el-table-column label="请求方式" align="center" prop="requestMethod" />
<el-table-column label="操作人员" align="center" prop="operName" width="100" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" /> <el-table-column label="操作人员" align="center" prop="operName" width="100" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
<el-table-column label="部门" align="center" prop="deptName" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" /> <el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
<el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" /> <el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
<el-table-column label="操作状态" align="center" prop="status"> <el-table-column label="操作状态" align="center" prop="status">
@ -150,15 +160,16 @@
<el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body> <el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
<el-form ref="form" :model="form" label-width="100px" size="mini"> <el-form ref="form" :model="form" label-width="100px" size="mini">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="24">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
<el-form-item <el-form-item
label="登录信息:" label="登录信息:"
>{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item> >{{ form.operName }} / {{form.deptName}} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item> <el-form-item label="请求信息:">{{ form.requestMethod }} {{form.operUrl }}</el-form-item>
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item> </el-col>
<el-col :span="12">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<el-form-item label="操作方法:">{{ form.method }}</el-form-item> <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
@ -222,6 +233,7 @@ export default {
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
operIp: undefined,
title: undefined, title: undefined,
operName: undefined, operName: undefined,
businessType: undefined, businessType: undefined,

View File

@ -246,7 +246,7 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12" v-if="form.menuType != 'F'"> <el-col :span="12">
<el-form-item prop="status"> <el-form-item prop="status">
<span slot="label"> <span slot="label">
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top"> <el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">

View File

@ -164,7 +164,7 @@
</el-form-item> </el-form-item>
<el-form-item prop="roleKey"> <el-form-item prop="roleKey">
<span slot="label"> <span slot="label">
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top"> <el-tooltip content="控制器中定义的权限字符,如:@SaCheckRole('admin')" placement="top">
<i class="el-icon-question"></i> <i class="el-icon-question"></i>
</el-tooltip> </el-tooltip>
权限字符 权限字符

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ruoyi-vue-plus</artifactId> <artifactId>ruoyi-vue-plus</artifactId>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<version>4.8.1</version> <version>4.8.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -110,12 +110,6 @@
<artifactId>easyexcel</artifactId> <artifactId>easyexcel</artifactId>
</dependency> </dependency>
<!-- yml解析器 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<!-- servlet包 --> <!-- servlet包 -->
<dependency> <dependency>
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>

View File

@ -29,17 +29,17 @@ public enum DataScopeType {
/** /**
* 自定数据权限 * 自定数据权限
*/ */
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", ""), CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
/** /**
* 部门数据权限 * 部门数据权限
*/ */
DEPT("3", " #{#deptName} = #{#user.deptId} ", ""), DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
/** /**
* 部门及以下数据权限 * 部门及以下数据权限
*/ */
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", ""), DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
/** /**
* 仅本人数据权限 * 仅本人数据权限

View File

@ -24,7 +24,7 @@ public class AddressUtils {
return UNKNOWN; return UNKNOWN;
} }
// 内网不查询 // 内网不查询
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip); ip = StringUtils.contains(ip, "0:0:0:0:0:0:0:1") ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
if (NetUtil.isInnerIP(ip)) { if (NetUtil.isInnerIP(ip)) {
return "内网IP"; return "内网IP";
} }

View File

@ -224,8 +224,12 @@ public class QueueUtils {
/** /**
* 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 ) * 订阅阻塞队列(可订阅所有实现类 例如: 延迟 优先 有界 )
*/ */
public static <T> void subscribeBlockingQueue(String queueName, Consumer<T> consumer) { public static <T> void subscribeBlockingQueue(String queueName, Consumer<T> consumer, boolean isDelayed) {
RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName); RBlockingQueue<T> queue = CLIENT.getBlockingQueue(queueName);
if (isDelayed) {
// 订阅延迟队列
CLIENT.getDelayedQueue(queue);
}
queue.subscribeOnElements(consumer); queue.subscribeOnElements(consumer);
} }

View File

@ -40,7 +40,7 @@ public class DelayedQueueController {
QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> { QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> {
// 观察接收时间 // 观察接收时间
log.info("通道: {}, 收到数据: {}", queueName, orderNum); log.info("通道: {}, 收到数据: {}", queueName, orderNum);
}); }, true);
return R.ok("操作成功"); return R.ok("操作成功");
} }

View File

@ -1,9 +1,12 @@
package com.ruoyi.framework.interceptor; package com.ruoyi.framework.interceptor;
import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils; import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport; import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.ruoyi.common.annotation.DataColumn;
import com.ruoyi.framework.handler.PlusDataPermissionHandler; import com.ruoyi.framework.handler.PlusDataPermissionHandler;
import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.delete.Delete; import net.sf.jsqlparser.statement.delete.Delete;
@ -23,6 +26,7 @@ import org.apache.ibatis.session.RowBounds;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Set;
/** /**
* 数据权限拦截器 * 数据权限拦截器
@ -33,6 +37,11 @@ import java.util.List;
public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor { public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {
private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler(); private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler();
/**
* 无效注解方法缓存用于快速返回
*/
private final Set<String> invalidCacheSet = new ConcurrentHashSet<>();
@Override @Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
@ -41,7 +50,12 @@ public class PlusDataPermissionInterceptor extends JsqlParserSupport implements
return; return;
} }
// 检查是否无效 无数据权限注解 // 检查是否无效 无数据权限注解
if (dataPermissionHandler.isInvalid(ms.getId())) { if (invalidCacheSet.contains(ms.getId())) {
return;
}
DataColumn[] dataColumns = dataPermissionHandler.findAnnotation(ms.getId());
if (ArrayUtil.isEmpty(dataColumns)) {
invalidCacheSet.add(ms.getId());
return; return;
} }
// 解析 sql 分配对应方法 // 解析 sql 分配对应方法
@ -58,6 +72,15 @@ public class PlusDataPermissionInterceptor extends JsqlParserSupport implements
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) { if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
return; return;
} }
// 检查是否无效 无数据权限注解
if (invalidCacheSet.contains(ms.getId())) {
return;
}
DataColumn[] dataColumns = dataPermissionHandler.findAnnotation(ms.getId());
if (ArrayUtil.isEmpty(dataColumns)) {
invalidCacheSet.add(ms.getId());
return;
}
PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql(); PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
mpBs.sql(parserMulti(mpBs.sql(), ms.getId())); mpBs.sql(parserMulti(mpBs.sql(), ms.getId()));
} }

View File

@ -44,14 +44,14 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
BufferedReader reader = request.getReader(); BufferedReader reader = request.getReader();
jsonParam = IoUtil.read(reader); jsonParam = IoUtil.read(reader);
} }
log.debug("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam); log.info("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
} else { } else {
Map<String, String[]> parameterMap = request.getParameterMap(); Map<String, String[]> parameterMap = request.getParameterMap();
if (MapUtil.isNotEmpty(parameterMap)) { if (MapUtil.isNotEmpty(parameterMap)) {
String parameters = JsonUtils.toJsonString(parameterMap); String parameters = JsonUtils.toJsonString(parameterMap);
log.debug("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters); log.info("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters);
} else { } else {
log.debug("[PLUS]开始请求 => URL[{}],无参数", url); log.info("[PLUS]开始请求 => URL[{}],无参数", url);
} }
} }
@ -72,7 +72,7 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
if (!prodProfile.equals(SpringUtils.getActiveProfile())) { if (!prodProfile.equals(SpringUtils.getActiveProfile())) {
StopWatch stopWatch = invokeTimeTL.get(); StopWatch stopWatch = invokeTimeTL.get();
stopWatch.stop(); stopWatch.stop();
log.debug("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime()); log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
invokeTimeTL.remove(); invokeTimeTL.remove();
} }
} }

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.annotation.Log; import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.event.OperLogEvent; import com.ruoyi.common.core.domain.event.OperLogEvent;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.enums.BusinessStatus;
import com.ruoyi.common.enums.HttpMethod; import com.ruoyi.common.enums.HttpMethod;
import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.common.helper.LoginHelper;
@ -74,7 +75,9 @@ public class LogAspect {
String ip = ServletUtils.getClientIP(); String ip = ServletUtils.getClientIP();
operLog.setOperIp(ip); operLog.setOperIp(ip);
operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255)); operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
operLog.setOperName(LoginHelper.getUsername()); LoginUser loginUser = LoginHelper.getLoginUser();
operLog.setOperName(loginUser.getUsername());
operLog.setDeptName(loginUser.getDeptName());
if (e != null) { if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setStatus(BusinessStatus.FAIL.ordinal());

View File

@ -50,8 +50,8 @@ public class SaTokenConfig implements WebMvcConfigurer {
// 有效率影响 用于临时测试 // 有效率影响 用于临时测试
// if (log.isDebugEnabled()) { // if (log.isDebugEnabled()) {
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout()); // log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());
// log.debug("临时有效时间: {}", StpUtil.getTokenActiveTimeout()); // log.info("临时有效时间: {}", StpUtil.getTokenActiveTimeout());
// } // }
}); });

View File

@ -2,8 +2,6 @@ package com.ruoyi.framework.handler;
import cn.hutool.core.annotation.AnnotationUtil; import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.annotation.DataColumn; import com.ruoyi.common.annotation.DataColumn;
@ -51,11 +49,6 @@ public class PlusDataPermissionHandler {
*/ */
private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>(); private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
/**
* 无效注解方法缓存用于快速返回
*/
private final Set<String> invalidCacheSet = new ConcurrentHashSet<>();
/** /**
* spel 解析器 * spel 解析器
*/ */
@ -69,10 +62,6 @@ public class PlusDataPermissionHandler {
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) { public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
DataColumn[] dataColumns = findAnnotation(mappedStatementId); DataColumn[] dataColumns = findAnnotation(mappedStatementId);
if (ArrayUtil.isEmpty(dataColumns)) {
invalidCacheSet.add(mappedStatementId);
return where;
}
LoginUser currentUser = DataPermissionHelper.getVariable("user"); LoginUser currentUser = DataPermissionHelper.getVariable("user");
if (ObjectUtil.isNull(currentUser)) { if (ObjectUtil.isNull(currentUser)) {
currentUser = LoginHelper.getLoginUser(); currentUser = LoginHelper.getLoginUser();
@ -156,7 +145,7 @@ public class PlusDataPermissionHandler {
return ""; return "";
} }
private DataColumn[] findAnnotation(String mappedStatementId) { public DataColumn[] findAnnotation(String mappedStatementId) {
StringBuilder sb = new StringBuilder(mappedStatementId); StringBuilder sb = new StringBuilder(mappedStatementId);
int index = sb.lastIndexOf("."); int index = sb.lastIndexOf(".");
String clazzName = sb.substring(0, index); String clazzName = sb.substring(0, index);
@ -190,10 +179,4 @@ public class PlusDataPermissionHandler {
return null; return null;
} }
/**
* 是否为无效方法 无数据权限
*/
public boolean isInvalid(String mappedStatementId) {
return invalidCacheSet.contains(mappedStatementId);
}
} }

View File

@ -78,7 +78,7 @@ public class GenController extends BaseController {
*/ */
@SaCheckPermission("tool:gen:list") @SaCheckPermission("tool:gen:list")
@GetMapping(value = "/column/{tableId}") @GetMapping(value = "/column/{tableId}")
public TableDataInfo<GenTableColumn> columnList(Long tableId) { public TableDataInfo<GenTableColumn> columnList(@PathVariable("tableId") Long tableId) {
TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>(); TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId); List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
dataInfo.setRows(list); dataInfo.setRows(list);

View File

@ -39,7 +39,7 @@ public class OssFactory {
/** /**
* 根据类型获取实例 * 根据类型获取实例
*/ */
public static OssClient instance(String configKey) { public static synchronized OssClient instance(String configKey) {
String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey); String json = CacheUtils.get(CacheNames.SYS_OSS_CONFIG, configKey);
if (json == null) { if (json == null) {
throw new OssException("系统异常, '" + configKey + "'配置信息不存在!"); throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");

View File

@ -49,11 +49,8 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
.apply(DataBaseHelper.findInSet(deptId, "ancestors"))); .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId); List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
ids.add(deptId); ids.add(deptId);
List<SysDept> list = deptMapper.selectList(new LambdaQueryWrapper<SysDept>() if (CollUtil.isNotEmpty(ids)) {
.select(SysDept::getDeptId) return StreamUtils.join(ids, Convert::toStr);
.in(SysDept::getDeptId, ids));
if (CollUtil.isNotEmpty(list)) {
return StreamUtils.join(list, d -> Convert.toStr(d.getDeptId()));
} }
return null; return null;
} }

View File

@ -437,7 +437,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
* 内链域名特殊字符替换 * 内链域名特殊字符替换
*/ */
public String innerLinkReplaceEach(String path) { public String innerLinkReplaceEach(String path) {
return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, "."}, return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"},
new String[]{"", "", "", "/"}); new String[]{"", "", "", "/", "/"});
} }
} }

View File

@ -51,6 +51,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery) { public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery) {
Map<String, Object> params = operLog.getParams(); Map<String, Object> params = operLog.getParams();
LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>() LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
.like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
.like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
.eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
SysOperLog::getBusinessType, operLog.getBusinessType()) SysOperLog::getBusinessType, operLog.getBusinessType())
@ -93,6 +94,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
public List<SysOperLog> selectOperLogList(SysOperLog operLog) { public List<SysOperLog> selectOperLogList(SysOperLog operLog) {
Map<String, Object> params = operLog.getParams(); Map<String, Object> params = operLog.getParams();
return baseMapper.selectList(new LambdaQueryWrapper<SysOperLog>() return baseMapper.selectList(new LambdaQueryWrapper<SysOperLog>()
.like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
.like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle()) .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
.eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0, .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
SysOperLog::getBusinessType, operLog.getBusinessType()) SysOperLog::getBusinessType, operLog.getBusinessType())

View File

@ -66,8 +66,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
for (Long id : ossIds) { for (Long id : ossIds) {
SysOssVo vo = SpringUtils.getAopProxy(this).getById(id); SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
if (ObjectUtil.isNotNull(vo)) { if (ObjectUtil.isNotNull(vo)) {
list.add(this.matchingUrl(vo)); try {
} list.add(this.matchingUrl(vo));
} catch (Exception ignored) {
// 如果oss异常无法连接则将数据直接返回
list.add(vo);
} }
} }
return list; return list;
} }
@ -78,7 +82,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) { for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
SysOssVo vo = SpringUtils.getAopProxy(this).getById(id); SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
if (ObjectUtil.isNotNull(vo)) { if (ObjectUtil.isNotNull(vo)) {
list.add(this.matchingUrl(vo).getUrl()); try {
list.add(this.matchingUrl(vo).getUrl());
} catch (Exception ignored) {
// 如果oss异常无法连接则将数据直接返回
list.add(vo.getUrl());
}
} }
} }
return String.join(StringUtils.SEPARATOR, list); return String.join(StringUtils.SEPARATOR, list);

View File

@ -195,9 +195,12 @@ public class SysRoleServiceImpl implements ISysRoleService {
if (ObjectUtil.isNotNull(role.getRoleId())) { if (ObjectUtil.isNotNull(role.getRoleId())) {
SysRole sysRole = baseMapper.selectById(role.getRoleId()); SysRole sysRole = baseMapper.selectById(role.getRoleId());
// 如果标识符不相等 判断为修改了管理员标识符 // 如果标识符不相等 判断为修改了管理员标识符
if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey()) if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) {
&& StringUtils.equals(sysRole.getRoleKey(), UserConstants.ADMIN_ROLE_KEY)) { if (StringUtils.equals(sysRole.getRoleKey(), UserConstants.ADMIN_ROLE_KEY)) {
throw new ServiceException("不允许修改系统内置管理员角色标识符!"); throw new ServiceException("不允许修改系统内置管理员角色标识符!");
} else if (StringUtils.equals(role.getRoleKey(), UserConstants.ADMIN_ROLE_KEY)) {
throw new ServiceException("不允许使用系统内置管理员角色标识符!");
}
} }
} }
} }

View File

@ -32,7 +32,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult"> <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
<if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()"> <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
select column_name, select column_name,
(case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null end) as is_required, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required,
(case when column_key = 'PRI' then '1' else '0' end) as is_pk, (case when column_key = 'PRI' then '1' else '0' end) as is_pk,
ordinal_position as sort, ordinal_position as sort,
column_comment, column_comment,
@ -43,7 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</if> </if>
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()"> <if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
select lower(temp.column_name) as column_name, select lower(temp.column_name) as column_name,
(case when (temp.nullable = 'N' and temp.constraint_type != 'P') then '1' else null end) as is_required, (case when (temp.nullable = 'N' and temp.constraint_type != 'P') then '1' else '0' end) as is_required,
(case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk, (case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk,
temp.column_id as sort, temp.column_id as sort,
temp.comments as column_comment, temp.comments as column_comment,

View File

@ -434,7 +434,7 @@ export default {
this.reset(); this.reset();
this.getTreeselect(); this.getTreeselect();
if (row != null && row.${treeCode}) { if (row != null && row.${treeCode}) {
this.form.${treeParentCode} = row.${treeParentCode}; this.form.${treeParentCode} = row.${treeCode};
} else { } else {
this.form.${treeParentCode} = 0; this.form.${treeParentCode} = 0;
} }
@ -455,7 +455,7 @@ export default {
this.reset(); this.reset();
this.getTreeselect(); this.getTreeselect();
if (row != null) { if (row != null) {
this.form.${treeParentCode} = row.${treeCode}; this.form.${treeParentCode} = row.${treeParentCode};
} }
get${BusinessName}(row.${pkColumn.javaField}).then(response => { get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.loading = false; this.loading = false;

View File

@ -398,7 +398,7 @@ function handleAdd(row) {
reset(); reset();
getTreeselect(); getTreeselect();
if (row != null && row.${treeCode}) { if (row != null && row.${treeCode}) {
form.value.${treeParentCode} = row.${treeParentCode}; form.value.${treeParentCode} = row.${treeCode};
} else { } else {
form.value.${treeParentCode} = 0; form.value.${treeParentCode} = 0;
} }
@ -421,7 +421,7 @@ async function handleUpdate(row) {
reset(); reset();
await getTreeselect(); await getTreeselect();
if (row != null) { if (row != null) {
form.value.${treeParentCode} = row.${treeCode}; form.value.${treeParentCode} = row.${treeParentCode};
} }
get${BusinessName}(row.${pkColumn.javaField}).then(response => { get${BusinessName}(row.${pkColumn.javaField}).then(response => {
loading.value = false; loading.value = false;

View File

@ -100,7 +100,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-server1: ruoyi-server1:
image: ruoyi/ruoyi-server:4.8.1 image: ruoyi/ruoyi-server:4.8.2
container_name: ruoyi-server1 container_name: ruoyi-server1
environment: environment:
# 时区上海 # 时区上海
@ -115,7 +115,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-server2: ruoyi-server2:
image: "ruoyi/ruoyi-server:4.8.1" image: "ruoyi/ruoyi-server:4.8.2"
container_name: ruoyi-server2 container_name: ruoyi-server2
environment: environment:
# 时区上海 # 时区上海
@ -130,7 +130,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-monitor-admin: ruoyi-monitor-admin:
image: ruoyi/ruoyi-monitor-admin:4.8.1 image: ruoyi/ruoyi-monitor-admin:4.8.2
container_name: ruoyi-monitor-admin container_name: ruoyi-monitor-admin
environment: environment:
# 时区上海 # 时区上海
@ -142,7 +142,7 @@ services:
network_mode: "host" network_mode: "host"
ruoyi-xxl-job-admin: ruoyi-xxl-job-admin:
image: ruoyi/ruoyi-xxl-job-admin:4.8.1 image: ruoyi/ruoyi-xxl-job-admin:4.8.2
container_name: ruoyi-xxl-job-admin container_name: ruoyi-xxl-job-admin
environment: environment:
# 时区上海 # 时区上海