😴发布 4.8.2 正式进入维护状态
This commit is contained in:
parent
a6f62ca86f
commit
267ff79b0c
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<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="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<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="sourceFilePath" value="ruoyi-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="ruoyi-xxl-job-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||
<deployment type="dockerfile">
|
||||
<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="sourceFilePath" value="ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile" />
|
||||
</settings>
|
||||
|
10
README.md
10
README.md
@ -3,6 +3,14 @@
|
||||
|
||||
- - -
|
||||
|
||||
## 版本状态说明
|
||||
|
||||
由于 springboot 2.X 与 vue 2.X 官方均宣布停止维护, 故而 框架 4.X 版本 进入维护状态(只处理问题不更新功能)
|
||||
|
||||
停止维护时间预计: 2024年6-10月具体根据使用人数动态决定, 此版本已经相当稳定 即便不更新功能也不影响使用
|
||||
|
||||
如果依旧选择使用 jdk8 或者 jdk11 可以放心使用此版本, 如果希望使用 jdk17 或者 jdk21 可以选择使用 5.X 分支
|
||||
|
||||
## 平台简介
|
||||
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
@ -10,7 +18,7 @@
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
|
||||
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
||||
<br>
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
|
28
pom.xml
28
pom.xml
@ -6,15 +6,15 @@
|
||||
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-vue-plus</artifactId>
|
||||
<version>4.8.1</version>
|
||||
<version>4.8.2</version>
|
||||
|
||||
<name>RuoYi-Vue-Plus</name>
|
||||
<url>https://gitee.com/dromara/RuoYi-Vue-Plus</url>
|
||||
<description>RuoYi-Vue-Plus后台管理系统</description>
|
||||
|
||||
<properties>
|
||||
<ruoyi-vue-plus.version>4.8.1</ruoyi-vue-plus.version>
|
||||
<spring-boot.version>2.7.16</spring-boot.version>
|
||||
<ruoyi-vue-plus.version>4.8.2</ruoyi-vue-plus.version>
|
||||
<spring-boot.version>2.7.18</spring-boot.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>1.8</java.version>
|
||||
@ -24,10 +24,10 @@
|
||||
<poi.version>5.2.3</poi.version>
|
||||
<easyexcel.version>3.3.2</easyexcel.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
<satoken.version>1.36.0</satoken.version>
|
||||
<mybatis-plus.version>3.5.3.2</mybatis-plus.version>
|
||||
<satoken.version>1.37.0</satoken.version>
|
||||
<mybatis-plus.version>3.5.4</mybatis-plus.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>
|
||||
<spring-boot-admin.version>2.7.11</spring-boot-admin.version>
|
||||
<redisson.version>3.20.1</redisson.version>
|
||||
@ -40,11 +40,8 @@
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>2.7.0</ip2region.version>
|
||||
|
||||
<!-- 临时修复 snakeyaml 漏洞 -->
|
||||
<snakeyaml.version>1.33</snakeyaml.version>
|
||||
|
||||
<!-- 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 配置 -->
|
||||
<sms4j.version>2.2.0</sms4j.version>
|
||||
</properties>
|
||||
@ -55,7 +52,7 @@
|
||||
<properties>
|
||||
<!-- 环境标识,需要与配置文件的名称相对应 -->
|
||||
<profiles.active>local</profiles.active>
|
||||
<logging.level>debug</logging.level>
|
||||
<logging.level>info</logging.level>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
@ -63,7 +60,7 @@
|
||||
<properties>
|
||||
<!-- 环境标识,需要与配置文件的名称相对应 -->
|
||||
<profiles.active>dev</profiles.active>
|
||||
<logging.level>debug</logging.level>
|
||||
<logging.level>info</logging.level>
|
||||
</properties>
|
||||
<activation>
|
||||
<!-- 默认环境 -->
|
||||
@ -261,13 +258,6 @@
|
||||
<version>${ip2region.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 临时修复 snakeyaml 漏洞 -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>${snakeyaml.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 加密包引入 -->
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>ruoyi-vue-plus</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>4.8.1</version>
|
||||
<version>4.8.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ruoyi-extend</artifactId>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>ruoyi-extend</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>4.8.1</version>
|
||||
<version>4.8.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ruoyi-extend</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>4.8.1</version>
|
||||
<version>4.8.2</version>
|
||||
</parent>
|
||||
<artifactId>ruoyi-xxl-job-admin</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ruoyi-vue-plus",
|
||||
"version": "4.8.1",
|
||||
"version": "4.8.2",
|
||||
"description": "RuoYi-Vue-Plus后台管理系统",
|
||||
"author": "LionLi",
|
||||
"license": "MIT",
|
||||
@ -15,7 +15,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "2.0.10",
|
||||
"@vueup/vue-quill": "1.1.0",
|
||||
"@vueup/vue-quill": "1.2.0",
|
||||
"@vueuse/core": "9.5.0",
|
||||
"axios": "0.27.2",
|
||||
"echarts": "5.4.0",
|
||||
|
@ -9,14 +9,13 @@
|
||||
name="file"
|
||||
:show-file-list="false"
|
||||
:headers="headers"
|
||||
style="display: none"
|
||||
ref="uploadRef"
|
||||
v-if="type == 'url'"
|
||||
>
|
||||
</el-upload>
|
||||
<div class="editor">
|
||||
<quill-editor
|
||||
ref="myQuillEditor"
|
||||
ref="quillEditorRef"
|
||||
v-model:content="content"
|
||||
contentType="html"
|
||||
@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 headers = ref({ Authorization: "Bearer " + getToken() });
|
||||
const myQuillEditor = ref();
|
||||
const quillEditorRef = ref();
|
||||
|
||||
const options = ref({
|
||||
theme: "snow",
|
||||
@ -101,7 +100,7 @@ const options = ref({
|
||||
},
|
||||
}
|
||||
},
|
||||
placeholder: '请输入内容',
|
||||
placeholder: "请输入内容",
|
||||
readOnly: props.readOnly,
|
||||
});
|
||||
|
||||
@ -114,7 +113,7 @@ const styles = computed(() => {
|
||||
style.height = `${props.height}px`;
|
||||
}
|
||||
return style;
|
||||
})
|
||||
});
|
||||
|
||||
const content = ref("");
|
||||
watch(() => props.modelValue, (v) => {
|
||||
@ -125,10 +124,10 @@ watch(() => props.modelValue, (v) => {
|
||||
|
||||
// 图片上传成功返回图片地址
|
||||
function handleUploadSuccess(res, file) {
|
||||
// 获取富文本实例
|
||||
let quill = toRaw(myQuillEditor.value).getQuill();
|
||||
// 如果上传成功
|
||||
if (res.code == 200) {
|
||||
// 获取富文本实例
|
||||
let quill = toRaw(quillEditorRef.value).getQuill();
|
||||
// 获取光标位置
|
||||
let length = quill.selection.savedRange.index;
|
||||
// 插入图片,res为服务器返回的图片链接地址
|
||||
@ -144,6 +143,13 @@ function handleUploadSuccess(res, 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) {
|
||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||
@ -164,6 +170,9 @@ function handleUploadError(err) {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.editor-img-uploader {
|
||||
display: none;
|
||||
}
|
||||
.editor, .ql-toolbar {
|
||||
white-space: pre-wrap !important;
|
||||
line-height: normal !important;
|
||||
|
@ -45,12 +45,17 @@ function close() {
|
||||
}
|
||||
function change(val) {
|
||||
const path = val.path;
|
||||
const query = val.query;
|
||||
if (isHttp(path)) {
|
||||
// http(s):// 路径新窗口打开
|
||||
const pindex = path.indexOf("http");
|
||||
window.open(path.substr(pindex, path.length), "_blank");
|
||||
} else {
|
||||
router.push(path)
|
||||
if (query) {
|
||||
router.push({ path: path, query: JSON.parse(query) });
|
||||
} else {
|
||||
router.push(path)
|
||||
}
|
||||
}
|
||||
|
||||
search.value = ''
|
||||
@ -77,7 +82,7 @@ function initFuse(list) {
|
||||
}
|
||||
// Filter out the routes that can be displayed in the sidebar
|
||||
// And generate the internationalized title
|
||||
function generateRoutes(routes, basePath = '', prefixTitle = []) {
|
||||
function generateRoutes(routes, basePath = '', prefixTitle = [], query = {}) {
|
||||
let res = []
|
||||
|
||||
for (const r of routes) {
|
||||
@ -99,9 +104,13 @@ function generateRoutes(routes, basePath = '', prefixTitle = []) {
|
||||
}
|
||||
}
|
||||
|
||||
if (r.query) {
|
||||
data.query = r.query
|
||||
}
|
||||
|
||||
// recursive child routes
|
||||
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) {
|
||||
res = [...res, ...tempRoutes]
|
||||
}
|
||||
@ -176,4 +185,4 @@ watch(searchPool, (list) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -5,15 +5,23 @@
|
||||
:key="item.path"
|
||||
:iframeId="'iframe' + index"
|
||||
v-show="route.path === item.path"
|
||||
:src="item.meta.link"
|
||||
:src="iframeUrl(item.meta.link, item.query)"
|
||||
></inner-link>
|
||||
</transition-group>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import InnerLink from "../InnerLink/index"
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
import InnerLink from "../InnerLink/index";
|
||||
import useTagsViewStore from "@/store/modules/tagsView";
|
||||
|
||||
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>
|
||||
|
@ -101,6 +101,10 @@ function filterChildren(childrenMap, lastRouter = false) {
|
||||
}
|
||||
if (lastRouter) {
|
||||
el.path = lastRouter.path + '/' + el.path
|
||||
if (el.children && el.children.length) {
|
||||
children = children.concat(filterChildren(el.children, el))
|
||||
return
|
||||
}
|
||||
}
|
||||
children = children.concat(el)
|
||||
})
|
||||
|
@ -7,6 +7,7 @@ const useUserStore = defineStore(
|
||||
{
|
||||
state: () => ({
|
||||
token: getToken(),
|
||||
id: '',
|
||||
name: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
@ -42,8 +43,9 @@ const useUserStore = defineStore(
|
||||
} else {
|
||||
this.roles = ['ROLE_DEFAULT']
|
||||
}
|
||||
this.id = user.userId
|
||||
this.name = user.userName
|
||||
this.avatar = avatar;
|
||||
this.avatar = avatar
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
@ -336,7 +336,7 @@ function submitForm() {
|
||||
proxy.$refs["demoRef"].validate(valid => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.ossConfigId != null) {
|
||||
if (form.value.id != null) {
|
||||
updateDemo(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
open.value = false;
|
||||
|
@ -243,7 +243,7 @@ function submitForm() {
|
||||
proxy.$refs["treeRef"].validate(valid => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
if (form.value.ossConfigId != null) {
|
||||
if (form.value.id != null) {
|
||||
updateTree(form.value).then(response => {
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
open.value = false;
|
||||
|
@ -103,7 +103,7 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Index">
|
||||
const version = ref('4.8.1')
|
||||
const version = ref('4.8.2')
|
||||
|
||||
function goTarget(url) {
|
||||
window.open(url, '__blank')
|
||||
|
@ -1,7 +1,16 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<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
|
||||
v-model="queryParams.title"
|
||||
placeholder="请输入系统模块"
|
||||
@ -107,9 +116,12 @@
|
||||
<dict-tag :options="sys_oper_type" :value="scope.row.businessType" />
|
||||
</template>
|
||||
</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" prop="operIp" width="130" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作状态" align="center" prop="status">
|
||||
<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="operLocation" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作状态" align="center" prop="status">
|
||||
<template #default="scope">
|
||||
<dict-tag :options="sys_common_status" :value="scope.row.status" />
|
||||
</template>
|
||||
@ -143,15 +155,16 @@
|
||||
<el-dialog title="操作日志详细" v-model="open" width="700px" append-to-body>
|
||||
<el-form :model="form" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
|
||||
<el-col :span="24">
|
||||
<el-form-item
|
||||
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 :span="12">
|
||||
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
|
||||
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
|
||||
<el-form-item label="请求信息:">{{ form.requestMethod }} {{form.operUrl }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="操作方法:">{{ form.method }}</el-form-item>
|
||||
@ -211,6 +224,7 @@ const data = reactive({
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
operIp: undefined,
|
||||
title: undefined,
|
||||
operName: undefined,
|
||||
businessType: undefined,
|
||||
|
@ -246,7 +246,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||
<el-col :span="12">
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span>
|
||||
|
@ -149,7 +149,7 @@
|
||||
<el-form-item prop="roleKey">
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
|
||||
<el-tooltip content="控制器中定义的权限字符,如:@SaCheckRole('admin')" placement="top">
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
权限字符
|
||||
|
@ -605,4 +605,7 @@ function submitForm() {
|
||||
|
||||
getDeptTree();
|
||||
getList();
|
||||
proxy.getConfigKey("sys.user.initPassword").then(response => {
|
||||
initPassword.value = response.msg;
|
||||
});
|
||||
</script>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ruoyi-vue-plus",
|
||||
"version": "4.8.1",
|
||||
"version": "4.8.2",
|
||||
"description": "RuoYi-Vue-Plus后台管理系统",
|
||||
"author": "LionLi",
|
||||
"license": "MIT",
|
||||
|
@ -47,7 +47,7 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 上传文件大小限制(MB)
|
||||
/* 上传文件大小限制(MB) */
|
||||
fileSize: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
@ -129,7 +129,6 @@ export default {
|
||||
if (this.type == 'url') {
|
||||
let toolbar = this.Quill.getModule("toolbar");
|
||||
toolbar.addHandler("image", (value) => {
|
||||
this.uploadType = "image";
|
||||
if (value) {
|
||||
this.$refs.upload.$children[0].$refs.input.click();
|
||||
} else {
|
||||
@ -158,6 +157,13 @@ export default {
|
||||
},
|
||||
// 上传前校检格式和大小
|
||||
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) {
|
||||
const isLt = file.size / 1024 / 1024 < this.fileSize;
|
||||
@ -169,10 +175,10 @@ export default {
|
||||
return true;
|
||||
},
|
||||
handleUploadSuccess(res, file) {
|
||||
// 获取富文本组件实例
|
||||
let quill = this.Quill;
|
||||
// 如果上传成功
|
||||
if (res.code == 200) {
|
||||
// 获取富文本组件实例
|
||||
let quill = this.Quill;
|
||||
// 获取光标所在位置
|
||||
let length = quill.getSelection().index;
|
||||
// 插入图片 res.url为服务器返回的图片地址
|
||||
|
@ -71,12 +71,17 @@ export default {
|
||||
},
|
||||
change(val) {
|
||||
const path = val.path;
|
||||
const query = val.query;
|
||||
if(this.ishttp(val.path)) {
|
||||
// http(s):// 路径新窗口打开
|
||||
const pindex = path.indexOf("http");
|
||||
window.open(path.substr(pindex, path.length), "_blank");
|
||||
} 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.options = []
|
||||
@ -102,7 +107,7 @@ export default {
|
||||
},
|
||||
// Filter out the routes that can be displayed in the sidebar
|
||||
// And generate the internationalized title
|
||||
generateRoutes(routes, basePath = '/', prefixTitle = []) {
|
||||
generateRoutes(routes, basePath = '/', prefixTitle = [], query = {}) {
|
||||
let res = []
|
||||
|
||||
for (const router of routes) {
|
||||
@ -124,9 +129,13 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
if (router.query) {
|
||||
data.query = router.query
|
||||
}
|
||||
|
||||
// recursive child routes
|
||||
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) {
|
||||
res = [...res, ...tempRoutes]
|
||||
}
|
||||
|
@ -5,19 +5,28 @@
|
||||
:key="item.path"
|
||||
:iframeId="'iframe' + index"
|
||||
v-show="$route.path === item.path"
|
||||
:src="item.meta.link"
|
||||
:src="iframeUrl(item.meta.link, item.query)"
|
||||
></inner-link>
|
||||
</transition-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import InnerLink from "../InnerLink/index"
|
||||
import InnerLink from "../InnerLink/index";
|
||||
|
||||
export default {
|
||||
components: { InnerLink },
|
||||
computed: {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,10 @@ function filterChildren(childrenMap, lastRouter = false) {
|
||||
}
|
||||
if (lastRouter) {
|
||||
el.path = lastRouter.path + '/' + el.path
|
||||
if (el.children && el.children.length) {
|
||||
children = children.concat(filterChildren(el.children, el))
|
||||
return
|
||||
}
|
||||
}
|
||||
children = children.concat(el)
|
||||
})
|
||||
|
@ -4,6 +4,7 @@ import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||
const user = {
|
||||
state: {
|
||||
token: getToken(),
|
||||
id: '',
|
||||
name: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
@ -14,6 +15,9 @@ const user = {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_ID: (state, id) => {
|
||||
state.id = id
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
},
|
||||
@ -58,6 +62,7 @@ const user = {
|
||||
} else {
|
||||
commit('SET_ROLES', ['ROLE_DEFAULT'])
|
||||
}
|
||||
commit('SET_ID', user.userId)
|
||||
commit('SET_NAME', user.userName)
|
||||
commit('SET_AVATAR', avatar)
|
||||
resolve(res)
|
||||
|
@ -114,7 +114,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
// 版本号
|
||||
version: "4.8.1",
|
||||
version: "4.8.2",
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
296
ruoyi-ui/src/views/monitor/cache/index.vue
vendored
296
ruoyi-ui/src/views/monitor/cache/index.vue
vendored
@ -1,148 +1,148 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row>
|
||||
<el-col :span="24" class="card-box">
|
||||
<el-card>
|
||||
<div slot="header"><span><i class="el-icon-monitor"></i> 基本信息</span></div>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<table cellspacing="0" style="width: 100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<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">运行模式</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" 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" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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">使用内存</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" 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" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
|
||||
</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" 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" 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" 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" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<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 ref="commandstats" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<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 ref="usedmemory" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCache } from "@/api/monitor/cache";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default {
|
||||
name: "Cache",
|
||||
data() {
|
||||
return {
|
||||
// 统计命令信息
|
||||
commandstats: null,
|
||||
// 使用内存
|
||||
usedmemory: null,
|
||||
// cache信息
|
||||
cache: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.openLoading();
|
||||
},
|
||||
methods: {
|
||||
/** 查缓存询信息 */
|
||||
getList() {
|
||||
getCache().then((response) => {
|
||||
this.cache = response.data;
|
||||
this.$modal.closeLoading();
|
||||
|
||||
this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
|
||||
this.commandstats.setOption({
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "命令",
|
||||
type: "pie",
|
||||
roseType: "radius",
|
||||
radius: [15, 95],
|
||||
center: ["50%", "38%"],
|
||||
data: response.data.commandStats,
|
||||
animationEasing: "cubicInOut",
|
||||
animationDuration: 1000,
|
||||
}
|
||||
]
|
||||
});
|
||||
this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
|
||||
this.usedmemory.setOption({
|
||||
tooltip: {
|
||||
formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "峰值",
|
||||
type: "gauge",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
detail: {
|
||||
formatter: this.cache.info.used_memory_human,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: parseFloat(this.cache.info.used_memory_human),
|
||||
name: "内存消耗",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
window.addEventListener("resize",()=>{
|
||||
this.commandstats.resize()
|
||||
this.usedmemory.resize()
|
||||
});
|
||||
});
|
||||
},
|
||||
// 打开加载层
|
||||
openLoading() {
|
||||
this.$modal.loading("正在加载缓存监控数据,请稍候!");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row>
|
||||
<el-col :span="24" class="card-box">
|
||||
<el-card>
|
||||
<div slot="header"><span><i class="el-icon-monitor"></i> 基本信息</span></div>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<table cellspacing="0" style="width: 100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<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">运行模式</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" 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" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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">使用内存</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" 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" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
|
||||
</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" 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" 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" 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" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<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 ref="commandstats" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12" class="card-box">
|
||||
<el-card>
|
||||
<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 ref="usedmemory" style="height: 420px" />
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCache } from "@/api/monitor/cache";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default {
|
||||
name: "Cache",
|
||||
data() {
|
||||
return {
|
||||
// 统计命令信息
|
||||
commandstats: null,
|
||||
// 使用内存
|
||||
usedmemory: null,
|
||||
// cache信息
|
||||
cache: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
this.openLoading();
|
||||
},
|
||||
methods: {
|
||||
/** 查缓存询信息 */
|
||||
getList() {
|
||||
getCache().then((response) => {
|
||||
this.cache = response.data;
|
||||
this.$modal.closeLoading();
|
||||
|
||||
this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
|
||||
this.commandstats.setOption({
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b} : {c} ({d}%)",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "命令",
|
||||
type: "pie",
|
||||
roseType: "radius",
|
||||
radius: [15, 95],
|
||||
center: ["50%", "38%"],
|
||||
data: response.data.commandStats,
|
||||
animationEasing: "cubicInOut",
|
||||
animationDuration: 1000,
|
||||
}
|
||||
]
|
||||
});
|
||||
this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
|
||||
this.usedmemory.setOption({
|
||||
tooltip: {
|
||||
formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "峰值",
|
||||
type: "gauge",
|
||||
min: 0,
|
||||
max: 1000,
|
||||
detail: {
|
||||
formatter: this.cache.info.used_memory_human,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: parseFloat(this.cache.info.used_memory_human),
|
||||
name: "内存消耗",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
window.addEventListener("resize",()=>{
|
||||
this.commandstats.resize()
|
||||
this.usedmemory.resize()
|
||||
});
|
||||
});
|
||||
},
|
||||
// 打开加载层
|
||||
openLoading() {
|
||||
this.$modal.loading("正在加载缓存监控数据,请稍候!");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,6 +1,15 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<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-input
|
||||
v-model="queryParams.title"
|
||||
@ -113,6 +122,7 @@
|
||||
</el-table-column>
|
||||
<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="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="operLocation" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="操作状态" align="center" prop="status">
|
||||
@ -150,15 +160,16 @@
|
||||
<el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
|
||||
<el-form ref="form" :model="form" label-width="100px" size="mini">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
|
||||
<el-col :span="24">
|
||||
<el-form-item
|
||||
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 :span="12">
|
||||
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
|
||||
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
|
||||
<el-form-item label="请求信息:">{{ form.requestMethod }} {{form.operUrl }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="操作方法:">{{ form.method }}</el-form-item>
|
||||
@ -222,6 +233,7 @@ export default {
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
operIp: undefined,
|
||||
title: undefined,
|
||||
operName: undefined,
|
||||
businessType: undefined,
|
||||
|
@ -246,7 +246,7 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12" v-if="form.menuType != 'F'">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="status">
|
||||
<span slot="label">
|
||||
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
||||
|
@ -164,7 +164,7 @@
|
||||
</el-form-item>
|
||||
<el-form-item prop="roleKey">
|
||||
<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>
|
||||
</el-tooltip>
|
||||
权限字符
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>ruoyi-vue-plus</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>4.8.1</version>
|
||||
<version>4.8.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
@ -110,12 +110,6 @@
|
||||
<artifactId>easyexcel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- yml解析器 -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- servlet包 -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
|
@ -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 "),
|
||||
|
||||
/**
|
||||
* 仅本人数据权限
|
||||
|
@ -24,7 +24,7 @@ public class AddressUtils {
|
||||
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)) {
|
||||
return "内网IP";
|
||||
}
|
||||
|
@ -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);
|
||||
if (isDelayed) {
|
||||
// 订阅延迟队列
|
||||
CLIENT.getDelayedQueue(queue);
|
||||
}
|
||||
queue.subscribeOnElements(consumer);
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ public class DelayedQueueController {
|
||||
QueueUtils.subscribeBlockingQueue(queueName, (String orderNum) -> {
|
||||
// 观察接收时间
|
||||
log.info("通道: {}, 收到数据: {}", queueName, orderNum);
|
||||
});
|
||||
}, true);
|
||||
return R.ok("操作成功");
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
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.toolkit.PluginUtils;
|
||||
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
import com.ruoyi.framework.handler.PlusDataPermissionHandler;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.statement.delete.Delete;
|
||||
@ -23,6 +26,7 @@ import org.apache.ibatis.session.RowBounds;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 数据权限拦截器
|
||||
@ -33,6 +37,11 @@ import java.util.List;
|
||||
public class PlusDataPermissionInterceptor extends JsqlParserSupport implements InnerInterceptor {
|
||||
|
||||
private final PlusDataPermissionHandler dataPermissionHandler = new PlusDataPermissionHandler();
|
||||
/**
|
||||
* 无效注解方法缓存用于快速返回
|
||||
*/
|
||||
private final Set<String> invalidCacheSet = new ConcurrentHashSet<>();
|
||||
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
// 检查是否无效 无数据权限注解
|
||||
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;
|
||||
}
|
||||
// 解析 sql 分配对应方法
|
||||
@ -58,6 +72,15 @@ public class PlusDataPermissionInterceptor extends JsqlParserSupport implements
|
||||
if (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) {
|
||||
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();
|
||||
mpBs.sql(parserMulti(mpBs.sql(), ms.getId()));
|
||||
}
|
||||
|
@ -44,14 +44,14 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
||||
BufferedReader reader = request.getReader();
|
||||
jsonParam = IoUtil.read(reader);
|
||||
}
|
||||
log.debug("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
|
||||
log.info("[PLUS]开始请求 => URL[{}],参数类型[json],参数:[{}]", url, jsonParam);
|
||||
} else {
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
if (MapUtil.isNotEmpty(parameterMap)) {
|
||||
String parameters = JsonUtils.toJsonString(parameterMap);
|
||||
log.debug("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters);
|
||||
log.info("[PLUS]开始请求 => URL[{}],参数类型[param],参数:[{}]", url, parameters);
|
||||
} 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())) {
|
||||
StopWatch stopWatch = invokeTimeTL.get();
|
||||
stopWatch.stop();
|
||||
log.debug("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
|
||||
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
|
||||
invokeTimeTL.remove();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
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.HttpMethod;
|
||||
import com.ruoyi.common.helper.LoginHelper;
|
||||
@ -74,7 +75,9 @@ public class LogAspect {
|
||||
String ip = ServletUtils.getClientIP();
|
||||
operLog.setOperIp(ip);
|
||||
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) {
|
||||
operLog.setStatus(BusinessStatus.FAIL.ordinal());
|
||||
|
@ -50,8 +50,8 @@ public class SaTokenConfig implements WebMvcConfigurer {
|
||||
|
||||
// 有效率影响 用于临时测试
|
||||
// if (log.isDebugEnabled()) {
|
||||
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
|
||||
// log.debug("临时有效时间: {}", StpUtil.getTokenActiveTimeout());
|
||||
// log.info("剩余有效时间: {}", StpUtil.getTokenTimeout());
|
||||
// log.info("临时有效时间: {}", StpUtil.getTokenActiveTimeout());
|
||||
// }
|
||||
|
||||
});
|
||||
|
@ -2,8 +2,6 @@ package com.ruoyi.framework.handler;
|
||||
|
||||
import cn.hutool.core.annotation.AnnotationUtil;
|
||||
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.ObjectUtil;
|
||||
import com.ruoyi.common.annotation.DataColumn;
|
||||
@ -51,11 +49,6 @@ public class PlusDataPermissionHandler {
|
||||
*/
|
||||
private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 无效注解方法缓存用于快速返回
|
||||
*/
|
||||
private final Set<String> invalidCacheSet = new ConcurrentHashSet<>();
|
||||
|
||||
/**
|
||||
* spel 解析器
|
||||
*/
|
||||
@ -69,10 +62,6 @@ public class PlusDataPermissionHandler {
|
||||
|
||||
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
||||
DataColumn[] dataColumns = findAnnotation(mappedStatementId);
|
||||
if (ArrayUtil.isEmpty(dataColumns)) {
|
||||
invalidCacheSet.add(mappedStatementId);
|
||||
return where;
|
||||
}
|
||||
LoginUser currentUser = DataPermissionHelper.getVariable("user");
|
||||
if (ObjectUtil.isNull(currentUser)) {
|
||||
currentUser = LoginHelper.getLoginUser();
|
||||
@ -156,7 +145,7 @@ public class PlusDataPermissionHandler {
|
||||
return "";
|
||||
}
|
||||
|
||||
private DataColumn[] findAnnotation(String mappedStatementId) {
|
||||
public DataColumn[] findAnnotation(String mappedStatementId) {
|
||||
StringBuilder sb = new StringBuilder(mappedStatementId);
|
||||
int index = sb.lastIndexOf(".");
|
||||
String clazzName = sb.substring(0, index);
|
||||
@ -190,10 +179,4 @@ public class PlusDataPermissionHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为无效方法 无数据权限
|
||||
*/
|
||||
public boolean isInvalid(String mappedStatementId) {
|
||||
return invalidCacheSet.contains(mappedStatementId);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public class GenController extends BaseController {
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:list")
|
||||
@GetMapping(value = "/column/{tableId}")
|
||||
public TableDataInfo<GenTableColumn> columnList(Long tableId) {
|
||||
public TableDataInfo<GenTableColumn> columnList(@PathVariable("tableId") Long tableId) {
|
||||
TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
|
||||
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
|
||||
dataInfo.setRows(list);
|
||||
|
@ -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);
|
||||
if (json == null) {
|
||||
throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");
|
||||
|
@ -49,11 +49,8 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
|
||||
.apply(DataBaseHelper.findInSet(deptId, "ancestors")));
|
||||
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||
ids.add(deptId);
|
||||
List<SysDept> list = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
||||
.select(SysDept::getDeptId)
|
||||
.in(SysDept::getDeptId, ids));
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
return StreamUtils.join(list, d -> Convert.toStr(d.getDeptId()));
|
||||
if (CollUtil.isNotEmpty(ids)) {
|
||||
return StreamUtils.join(ids, Convert::toStr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -437,7 +437,7 @@ public class SysMenuServiceImpl implements ISysMenuService {
|
||||
* 内链域名特殊字符替换
|
||||
*/
|
||||
public String innerLinkReplaceEach(String path) {
|
||||
return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, "."},
|
||||
new String[]{"", "", "", "/"});
|
||||
return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"},
|
||||
new String[]{"", "", "", "/", "/"});
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
|
||||
public TableDataInfo<SysOperLog> selectPageOperLogList(SysOperLog operLog, PageQuery pageQuery) {
|
||||
Map<String, Object> params = operLog.getParams();
|
||||
LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
|
||||
.like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
|
||||
.like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
|
||||
.eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
|
||||
SysOperLog::getBusinessType, operLog.getBusinessType())
|
||||
@ -93,6 +94,7 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
|
||||
public List<SysOperLog> selectOperLogList(SysOperLog operLog) {
|
||||
Map<String, Object> params = operLog.getParams();
|
||||
return baseMapper.selectList(new LambdaQueryWrapper<SysOperLog>()
|
||||
.like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
|
||||
.like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
|
||||
.eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
|
||||
SysOperLog::getBusinessType, operLog.getBusinessType())
|
||||
|
@ -66,8 +66,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
for (Long id : ossIds) {
|
||||
SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
|
||||
if (ObjectUtil.isNotNull(vo)) {
|
||||
list.add(this.matchingUrl(vo));
|
||||
}
|
||||
try {
|
||||
list.add(this.matchingUrl(vo));
|
||||
} catch (Exception ignored) {
|
||||
// 如果oss异常无法连接则将数据直接返回
|
||||
list.add(vo);
|
||||
} }
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@ -78,7 +82,12 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
|
||||
for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
|
||||
SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
|
||||
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);
|
||||
|
@ -195,9 +195,12 @@ public class SysRoleServiceImpl implements ISysRoleService {
|
||||
if (ObjectUtil.isNotNull(role.getRoleId())) {
|
||||
SysRole sysRole = baseMapper.selectById(role.getRoleId());
|
||||
// 如果标识符不相等 判断为修改了管理员标识符
|
||||
if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())
|
||||
&& StringUtils.equals(sysRole.getRoleKey(), UserConstants.ADMIN_ROLE_KEY)) {
|
||||
throw new ServiceException("不允许修改系统内置管理员角色标识符!");
|
||||
if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) {
|
||||
if (StringUtils.equals(sysRole.getRoleKey(), UserConstants.ADMIN_ROLE_KEY)) {
|
||||
throw new ServiceException("不允许修改系统内置管理员角色标识符!");
|
||||
} else if (StringUtils.equals(role.getRoleKey(), UserConstants.ADMIN_ROLE_KEY)) {
|
||||
throw new ServiceException("不允许使用系统内置管理员角色标识符!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
|
||||
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,
|
||||
ordinal_position as sort,
|
||||
column_comment,
|
||||
@ -43,7 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</if>
|
||||
<if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
|
||||
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,
|
||||
temp.column_id as sort,
|
||||
temp.comments as column_comment,
|
||||
|
@ -434,7 +434,7 @@ export default {
|
||||
this.reset();
|
||||
this.getTreeselect();
|
||||
if (row != null && row.${treeCode}) {
|
||||
this.form.${treeParentCode} = row.${treeParentCode};
|
||||
this.form.${treeParentCode} = row.${treeCode};
|
||||
} else {
|
||||
this.form.${treeParentCode} = 0;
|
||||
}
|
||||
@ -455,7 +455,7 @@ export default {
|
||||
this.reset();
|
||||
this.getTreeselect();
|
||||
if (row != null) {
|
||||
this.form.${treeParentCode} = row.${treeCode};
|
||||
this.form.${treeParentCode} = row.${treeParentCode};
|
||||
}
|
||||
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
|
||||
this.loading = false;
|
||||
|
@ -398,7 +398,7 @@ function handleAdd(row) {
|
||||
reset();
|
||||
getTreeselect();
|
||||
if (row != null && row.${treeCode}) {
|
||||
form.value.${treeParentCode} = row.${treeParentCode};
|
||||
form.value.${treeParentCode} = row.${treeCode};
|
||||
} else {
|
||||
form.value.${treeParentCode} = 0;
|
||||
}
|
||||
@ -421,7 +421,7 @@ async function handleUpdate(row) {
|
||||
reset();
|
||||
await getTreeselect();
|
||||
if (row != null) {
|
||||
form.value.${treeParentCode} = row.${treeCode};
|
||||
form.value.${treeParentCode} = row.${treeParentCode};
|
||||
}
|
||||
get${BusinessName}(row.${pkColumn.javaField}).then(response => {
|
||||
loading.value = false;
|
||||
|
@ -100,7 +100,7 @@ services:
|
||||
network_mode: "host"
|
||||
|
||||
ruoyi-server1:
|
||||
image: ruoyi/ruoyi-server:4.8.1
|
||||
image: ruoyi/ruoyi-server:4.8.2
|
||||
container_name: ruoyi-server1
|
||||
environment:
|
||||
# 时区上海
|
||||
@ -115,7 +115,7 @@ services:
|
||||
network_mode: "host"
|
||||
|
||||
ruoyi-server2:
|
||||
image: "ruoyi/ruoyi-server:4.8.1"
|
||||
image: "ruoyi/ruoyi-server:4.8.2"
|
||||
container_name: ruoyi-server2
|
||||
environment:
|
||||
# 时区上海
|
||||
@ -130,7 +130,7 @@ services:
|
||||
network_mode: "host"
|
||||
|
||||
ruoyi-monitor-admin:
|
||||
image: ruoyi/ruoyi-monitor-admin:4.8.1
|
||||
image: ruoyi/ruoyi-monitor-admin:4.8.2
|
||||
container_name: ruoyi-monitor-admin
|
||||
environment:
|
||||
# 时区上海
|
||||
@ -142,7 +142,7 @@ services:
|
||||
network_mode: "host"
|
||||
|
||||
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
|
||||
environment:
|
||||
# 时区上海
|
||||
|
Loading…
x
Reference in New Issue
Block a user