34 Commits

Author SHA1 Message Date
RuoYi
f9d754c886 若依 3.8.1 2021-12-31 00:00:09 +08:00
RuoYi
13a5bf8585 修复显示详情信息出现的报错 2021-12-30 15:55:02 +08:00
RuoYi
fa97ed9e2c 新增文件上传组件 2021-12-30 13:50:57 +08:00
RuoYi
cda383534e 新增图片预览组件 2021-12-30 10:51:17 +08:00
RuoYi
61161cdd69 新增图片上传组件 2021-12-30 10:25:40 +08:00
RuoYi
ec4170a4f1 开启通过ip访问的配置 2021-12-30 09:54:06 +08:00
若依
fece6740a4 Merge pull request #5 from littleshe/patch-1
[fix]logo跳转404问题
2021-12-30 09:46:34 +08:00
RuoYi
bb3f449388 修正单词拼写错误 2021-12-29 15:53:30 +08:00
RuoYi
3d7b36932e 用户管理部门查询选择节点后分页参数初始 2021-12-29 15:50:15 +08:00
RuoYi
03a06c3415 定时任务文字修正 2021-12-28 14:56:35 +08:00
RuoYi
6cf9c3ffb6 新增使用Gzip解压缩静态文件地址 2021-12-20 14:47:53 +08:00
RuoYi
5621ea4a29 修复浏览器刷新后页面切换页签无法加载问题 2021-12-18 21:48:05 +08:00
RuoYi
a2aa467030 升级vite-plugin-compression到最新版本0.3.6 2021-12-18 19:16:24 +08:00
RuoYi
f5f717d0d4 升级dart-sass到版本1.45.0 2021-12-18 19:13:35 +08:00
RuoYi
fc372111ae 升级unplugin-auto-import到最新版本0.5.3 2021-12-18 19:09:27 +08:00
RuoYi
ce3c9ef16d 升级echarts到最新版本5.2.2 2021-12-17 15:09:52 +08:00
RuoYi
f13899808f 升级vue到最新版本3.2.26 2021-12-17 15:02:32 +08:00
RuoYi
475e27f4a6 replace @element-plus/icons with @element-plus/icons-vue 2021-12-17 14:43:30 +08:00
RuoYi
f3b1470a5c 升级element-plus到最新版本1.2.0-beta.6 2021-12-17 14:28:14 +08:00
RuoYi
d366a5046d 修复分页选择条/页数不生效问题 2021-12-17 12:08:17 +08:00
RuoYi
02b0bd0ec6 修复菜单图标缺少的prop属性 2021-12-17 12:05:55 +08:00
RuoYi
463011bb66 删除在线用户多余的代码 2021-12-16 15:14:58 +08:00
RuoYi
e170ac272d 代码生成预览溢出显示滚动条 2021-12-15 14:44:05 +08:00
RuoYi
c246d868a9 修改主题颜色按钮尺寸 2021-12-15 14:43:56 +08:00
RuoYi
b6744f8f99 用户导入提示溢出则显示滚动条 2021-12-15 14:43:02 +08:00
RuoYi
674a483ae7 优化下载解析blob异常提示 2021-12-10 10:07:21 +08:00
RuoYi
0c103e53b9 🎉 RuoYi-Cloud-Vue3(Vue3 Element Plus Vite)版本 2021-12-08 17:10:25 +08:00
RuoYi
6db6cecb17 🎉 RuoYi-Vue3(Vue3 Element Plus Vite)版本 2021-12-07 14:58:29 +08:00
RuoYi
6222fb6614 修正用户分配角色属性错误 2021-12-06 20:33:47 +08:00
RuoYi
03fe9f42d9 修复代码生成模板预览格式问题 2021-12-06 17:11:31 +08:00
urrrich
f8037c23ba [fix]logo跳转404问题 2021-12-06 15:57:21 +08:00
若依
f2cf400c8b 🎉 RuoYi-Vue3(Vue3 Element Plus Vite)版本 2021-12-01 17:43:45 +08:00
若依
25e801e579 Delete src/layout/components/tagsView directory
🎉 RuoYi-Vue3(Vue3 Element Plus Vite)版本
2021-12-01 17:43:19 +08:00
RuoYi
3ddb5e9b38 文件夹目录大写 2021-12-01 17:36:12 +08:00
31 changed files with 599 additions and 39 deletions

View File

@@ -8,4 +8,4 @@ VITE_APP_ENV = 'production'
VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip,brotli
VITE_BUILD_COMPRESS = gzip

View File

@@ -8,4 +8,4 @@ VITE_APP_ENV = 'staging'
VITE_APP_BASE_API = '/stage-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip,brotli
VITE_BUILD_COMPRESS = gzip

View File

@@ -1,6 +1,6 @@
{
"name": "ruoyi",
"version": "3.8.0",
"version": "3.8.1",
"description": "若依管理系统",
"author": "若依",
"license": "MIT",
@@ -15,17 +15,16 @@
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
},
"dependencies": {
"@element-plus/icons": "0.0.11",
"@vueuse/core": "6.4.1",
"@element-plus/icons-vue": "0.2.4",
"axios": "0.24.0",
"echarts": "5.2.1",
"element-plus": "1.2.0-beta.3",
"echarts": "5.2.2",
"element-plus": "1.2.0-beta.6",
"file-saver": "2.0.5",
"fuse.js": "6.4.6",
"js-cookie": "3.0.1",
"jsencrypt": "3.2.1",
"nprogress": "0.2.0",
"vue": "3.2.22",
"vue": "3.2.26",
"vue-cropper": "1.0.2",
"vue-router": "4.0.12",
"vuex": "4.0.2"
@@ -33,10 +32,10 @@
"devDependencies": {
"@vitejs/plugin-vue": "1.9.4",
"@vue/compiler-sfc": "3.2.22",
"sass": "1.43.4",
"unplugin-auto-import": "0.4.18",
"sass": "1.45.0",
"unplugin-auto-import": "0.5.3",
"vite": "2.6.14",
"vite-plugin-compression": "0.3.5",
"vite-plugin-compression": "0.3.6",
"vite-plugin-svg-icons": "1.0.5",
"vite-plugin-vue-setup-extend": "0.1.0"
}

View File

@@ -1,5 +1,5 @@
import request from '@/utils/request'
import { praseStrEmpty } from "@/utils/ruoyi";
import { parseStrEmpty } from "@/utils/ruoyi";
// 查询用户列表
export function listUser(query) {
@@ -13,7 +13,7 @@ export function listUser(query) {
// 查询用户详细
export function getUser(userId) {
return request({
url: '/system/user/' + praseStrEmpty(userId),
url: '/system/user/' + parseStrEmpty(userId),
method: 'get'
})
}

View File

@@ -64,7 +64,7 @@
margin-top: 6vh !important;
}
.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
.el-dialog.scrollbar .el-dialog__body {
overflow: auto;
overflow-x: hidden;
max-height: 70vh;

View File

@@ -0,0 +1,188 @@
<template>
<div class="upload-file">
<el-upload
:action="uploadFileUrl"
:before-upload="handleBeforeUpload"
:file-list="fileList"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-success="handleUploadSuccess"
:show-file-list="false"
:headers="headers"
class="upload-file-uploader"
ref="upload"
>
<!-- 上传按钮 -->
<el-button size="mini" type="primary">选取文件</el-button>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
<template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
的文件
</div>
</el-upload>
<!-- 文件列表 -->
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
<el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
</el-link>
<div class="ele-upload-list__item-content-action">
<el-link :underline="false" @click="handleDelete(index)" type="danger">删除</el-link>
</div>
</li>
</transition-group>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
const props = defineProps({
modelValue: [String, Object, Array],
// 数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["doc", "xls", "ppt", "txt", "pdf"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
}
});
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
watch(() => props.modelValue, val => {
if (val) {
let temp = 1;
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(',');
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === "string") {
item = { name: item, url: item };
}
item.uid = item.uid || new Date().getTime() + temp++;
return item;
});
} else {
fileList.value = [];
return [];
}
});
// 上传前校检格式和大小
function handleBeforeUpload(file) {
// 校检文件类型
if (props.fileType.length) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
const isTypeOk = props.fileType.some((type) => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
if (!isTypeOk) {
proxy.$modal.msgError(`文件格式不正确, 请上传${props.fileType.join("/")}格式文件!`);
return false;
}
}
// 校检文件大小
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy.$modal.msgError(`上传文件大小不能超过 ${props.fileSize} MB!`);
return false;
}
}
return true;
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}
// 上传失败
function handleUploadError(err) {
proxy.$modal.msgError("上传失败");
}
// 上传成功回调
function handleUploadSuccess(res, file) {
proxy.$modal.msgSuccess("上传成功");
fileList.value.push({ name: res.fileName, url: res.fileName });
emit("update:modelValue", listToString(fileList.value));
}
// 删除文件
function handleDelete(index) {
fileList.value.splice(index, 1);
emit("update:modelValue", listToString(fileList.value));
}
// 获取文件名称
function getFileName(name) {
if (name.lastIndexOf("/") > -1) {
return name.slice(name.lastIndexOf("/") + 1).toLowerCase();
} else {
return "";
}
}
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url + separator;
}
return strs != '' ? strs.substr(0, strs.length - 1) : '';
}
</script>
<style scoped lang="scss">
.upload-file-uploader {
margin-bottom: 5px;
}
.upload-file-list .el-upload-list__item {
border: 1px solid #e4e7ed;
line-height: 2;
margin-bottom: 10px;
position: relative;
}
.upload-file-list .ele-upload-list__item-content {
display: flex;
justify-content: space-between;
align-items: center;
color: inherit;
}
.ele-upload-list__item-content-action .el-link {
margin-right: 10px;
}
</style>

View File

@@ -0,0 +1,67 @@
<template>
<el-image :src="`${realSrc}`" fit="cover" :style="`width:${realWidth};height:${realHeight};`" :preview-src-list="[`${realSrc}`]">
<template #error>
<div class="image-slot">
<el-icon><picture-filled /></el-icon>
</div>
</template>
</el-image>
</template>
<script setup>
import { isExternal } from '@/utils/validate'
const props = defineProps({
src: {
type: String,
required: true
},
width: {
type: [Number, String],
default: ''
},
height: {
type: [Number, String],
default: ''
}
});
const realSrc = computed(() => {
if (isExternal(props.src)) {
return props.src
}
return import.meta.env.VITE_APP_BASE_API + props.src
})
const realWidth = computed(
() => typeof props.width == 'string' ? props.width : `${props.width}px`
);
const realHeight = computed(
() => typeof props.height == 'string' ? props.height : `${props.height}px`
);
</script>
<style lang="scss" scoped>
.el-image {
border-radius: 5px;
background-color: #ebeef5;
box-shadow: 0 0 5px 1px #ccc;
:deep(.el-image__inner) {
transition: all 0.3s;
cursor: pointer;
&:hover {
transform: scale(1.2);
}
}
:deep(.image-slot) {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
color: #909399;
font-size: 30px;
}
}
</style>

View File

@@ -0,0 +1,197 @@
<template>
<div class="component-upload-image">
<el-upload
:action="uploadImgUrl"
list-type="picture-card"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
name="file"
:on-remove="handleRemove"
:show-file-list="true"
:headers="headers"
:file-list="fileList"
:on-preview="handlePictureCardPreview"
:class="{ hide: fileList.length >= limit }"
>
<el-icon class="avatar-uploader-icon"><plus /></el-icon>
</el-upload>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件
</div>
<el-dialog
v-model="dialogVisible"
title="预览"
width="800px"
append-to-body
>
<img
:src="dialogImageUrl"
style="display: block; max-width: 100%; margin: 0 auto"
/>
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
const props = defineProps({
modelValue: [String, Object, Array],
// 图片数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ["png", "jpg", "jpeg"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
});
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
watch(() => props.modelValue, val => {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(",");
// 然后将数组转为对象数组
fileList.value = list.map(item => {
if (typeof item === "string") {
if (item.indexOf(baseUrl) === -1) {
item = { name: baseUrl + item, url: baseUrl + item };
} else {
item = { name: item, url: item };
}
}
return item;
});
} else {
fileList.value = [];
return [];
}
});
// 删除图片
function handleRemove(file, files) {
const findex = fileList.value.map(f => f.name).indexOf(file.name);
if (findex > -1) {
fileList.value.splice(findex, 1);
emit("update:modelValue", listToString(fileList.value));
}
}
// 上传成功回调
function handleUploadSuccess(res) {
fileList.value.push({ name: res.fileName, url: res.fileName });
emit("update:modelValue", listToString(fileList.value));
proxy.$modal.closeLoading();
}
// 上传前loading加载
function handleBeforeUpload(file) {
let isImg = false;
if (props.fileType.length) {
let fileExtension = "";
if (file.name.lastIndexOf(".") > -1) {
fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
}
isImg = props.fileType.some(type => {
if (file.type.indexOf(type) > -1) return true;
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
});
} else {
isImg = file.type.indexOf("image") > -1;
}
if (!isImg) {
proxy.$modal.msgError(
`文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
);
return false;
}
if (props.fileSize) {
const isLt = file.size / 1024 / 1024 < props.fileSize;
if (!isLt) {
proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
return false;
}
}
proxy.$modal.loading("上传中");
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}
// 上传失败
function handleUploadError() {
proxy.$modal.msgError("上传失败");
proxy.$modal.closeLoading();
}
// 预览
function handlePictureCardPreview(file) {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
}
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
strs += list[i].url.replace(baseUrl, "") + separator;
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {
display: none;
}
// 去掉动画效果
:deep(.el-list-enter-active),
:deep(.el-list-leave-active) {
transition: all 0s;
}
:deep(.el-list-enter, .el-list-leave-active) {
opacity: 0;
transform: translateY(0);
}
</style>

View File

@@ -3,7 +3,7 @@
<el-pagination
:background="background"
v-model:current-page="currentPage"
:page-size="pageSize"
v-model:page-size="pageSize"
:layout="layout"
:page-sizes="pageSizes"
:pager-count="pagerCount"

View File

@@ -1,4 +1,5 @@
import * as components from "@element-plus/icons";
import * as components from '@element-plus/icons-vue'
export default {
install: (app) => {
for (const key in components) {

View File

@@ -12,6 +12,8 @@
<script setup>
let store = useStore()
const route = useRoute()
store.dispatch('tagsView/addCachedView', route)
const cachedViews = computed(() => {
return store.state.tagsView.cachedViews
})

View File

@@ -28,7 +28,7 @@
<div class="drawer-item">
<span>主题颜色</span>
<span class="comp-style">
<el-color-picker v-model="theme" :predefine="predefineColors" @change="themeChange"/>
<el-color-picker size="small" v-model="theme" :predefine="predefineColors" @change="themeChange"/>
</span>
</div>
<el-divider />

View File

@@ -13,7 +13,7 @@
const tagAndTagSpacing = ref(4);
const { proxy } = getCurrentInstance();
const scrollWrapper = computed(() => proxy.$refs.scrollContainer.$refs.wrap);
const scrollWrapper = computed(() => proxy.$refs.scrollContainer.$refs.wrap$);
onMounted(() => {
scrollWrapper.value.addEventListener('scroll', emitScroll, true)

View File

@@ -31,6 +31,12 @@ import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel } from
import Pagination from '@/components/Pagination'
// 自定义表格工具组件
import RightToolbar from '@/components/RightToolbar'
// 文件上传组件
import FileUpload from "@/components/FileUpload"
// 图片上传组件
import ImageUpload from "@/components/ImageUpload"
// 图片预览组件
import ImagePreview from "@/components/ImagePreview"
// 自定义树选择组件
import TreeSelect from '@/components/TreeSelect'
// 字典标签组件
@@ -51,6 +57,9 @@ app.config.globalProperties.selectDictLabel = selectDictLabel
app.component('DictTag', DictTag)
app.component('Pagination', Pagination)
app.component('TreeSelect', TreeSelect)
app.component('FileUpload', FileUpload)
app.component('ImageUpload', ImageUpload)
app.component('ImagePreview', ImagePreview)
app.component('RightToolbar', RightToolbar)
app.use(router)

View File

@@ -2,6 +2,7 @@ import axios from 'axios'
import { ElMessage } from 'element-plus'
import { saveAs } from 'file-saver'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { blobValidate } from '@/utils/ruoyi'
const baseURL = import.meta.env.VITE_APP_BASE_API
@@ -15,12 +16,12 @@ export default {
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then(async (res) => {
const isLogin = await this.blobValidate(res.data);
const isLogin = await blobValidate(res.data);
if (isLogin) {
const blob = new Blob([res.data])
this.saveAs(blob, decodeURI(res.headers['download-filename']))
} else {
ElMessage.error('无效的会话,或者会话已过期,请重新登录。');
this.printErrMsg(res.data);
}
})
},
@@ -32,12 +33,12 @@ export default {
responseType: 'blob',
headers: { 'Authorization': 'Bearer ' + getToken() }
}).then(async (res) => {
const isLogin = await this.blobValidate(res.data);
const isLogin = await blobValidate(res.data);
if (isLogin) {
const blob = new Blob([res.data])
this.saveAs(blob, decodeURI(res.headers['download-filename']))
} else {
ElMessage.error('无效的会话,或者会话已过期,请重新登录。');
this.printErrMsg(res.data);
}
})
},
@@ -54,12 +55,18 @@ export default {
const blob = new Blob([res.data], { type: 'application/zip' })
this.saveAs(blob, name)
} else {
ElMessage.error('无效的会话,或者会话已过期,请重新登录。');
this.printErrMsg(res.data);
}
})
},
saveAs(text, name, opts) {
saveAs(text, name, opts);
},
async printErrMsg(data) {
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
ElMessage.error(errMsg);
}
}

View File

@@ -57,7 +57,7 @@ export const constantRoutes = [
{
path: '',
component: Layout,
redirect: 'index',
redirect: '/index',
children: [
{
path: '/index',
@@ -160,4 +160,4 @@ const router = createRouter({
},
});
export default router;
export default router;

View File

@@ -108,12 +108,15 @@ export function download(url, params, filename) {
const blob = new Blob([data])
saveAs(blob, filename)
} else {
ELMessage.error('无效的会话,或者会话已过期,请重新登录。');
const resText = await data.text();
const rspObj = JSON.parse(resText);
const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
ElMessage.error(errMsg);
}
downloadLoadingInstance.close();
}).catch((r) => {
console.error(r)
ELMessage.error('下载文件出现错误,请联系管理员!')
ElMessage.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close();
})
}

View File

@@ -110,7 +110,7 @@ export function sprintf(str) {
}
// 转换字符串undefined,null等转化为""
export function praseStrEmpty(str) {
export function parseStrEmpty(str) {
if (!str || str == "undefined" || str == "null") {
return "";
}

View File

@@ -151,6 +151,92 @@
</div>
</template>
<el-collapse accordion>
<el-collapse-item title="v3.8.1 - 2022-01-01">
<ol>
<li>新增Vue3前端代码生成模板</li>
<li>新增图片预览组件</li>
<li>新增压缩插件实现打包Gzip</li>
<li>自定义xss校验注解实现</li>
<li>自定义文字复制剪贴指令</li>
<li>代码生成预览支持复制内容</li>
<li>路由支持单独配置菜单或角色权限</li>
<li>用户管理部门查询选择节点后分页参数初始</li>
<li>修复用户分配角色属性错误</li>
<li>修复打包后字体图标偶现的乱码问题</li>
<li>修复菜单管理重置表单出现的错误</li>
<li>修复版本差异导致的懒加载报错问题</li>
<li>修复Cron组件中周回显问题</li>
<li>修复定时任务多参数逗号分隔的问题</li>
<li>修复根据ID查询列表可能出现的主键溢出问题</li>
<li>修复tomcat配置参数已过期问题</li>
<li>升级clipboard到最新版本2.0.8</li>
<li>升级oshi到最新版本v5.8.6</li>
<li>升级fastjson到最新版1.2.79</li>
<li>升级spring-boot到最新版本2.5.8</li>
<li>升级log4j2到2.17.1防止漏洞风险</li>
<li>优化下载解析blob异常提示</li>
<li>优化代码生成字典组重复问题</li>
<li>优化查询用户的角色组&岗位组代码</li>
<li>优化定时任务cron表达式小时设置24</li>
<li>优化用户导入提示溢出则显示滚动条</li>
<li>优化防重复提交标识组合为(key+url+header)</li>
<li>优化分页方法设置成通用方便灵活调用</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.8.0 - 2021-12-01">
<ol>
<li>新增配套并同步的Vue3前端版本</li>
<li>新增通用方法简化模态/缓存/下载/权限/页签使用</li>
<li>优化导出数据/使用通用下载方法</li>
<li>Excel注解支持自定义数据处理器</li>
<li>Excel注解支持导入导出标题信息</li>
<li>Excel导入支持@Excels注解</li>
<li>新增组件data-dict简化数据字典使用</li>
<li>新增Jaxb依赖防止jdk8以上出现的兼容错误</li>
<li>生产环境使用路由懒加载提升页面响应速度</li>
<li>修复五级以上菜单出现的404问题</li>
<li>防重提交注解支持配置间隔时间/提示消息</li>
<li>日志注解新增是否保存响应参数</li>
<li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
<li>升级SpringBoot到最新版本2.5.6</li>
<li>升级pagehelper到最新版1.4.0</li>
<li>升级spring-boot-mybatis到最新版2.2.0</li>
<li>升级oshi到最新版本v5.8.2</li>
<li>升级druid到最新版1.2.8</li>
<li>升级velocity到最新版本2.3</li>
<li>升级fastjson到最新版1.2.78</li>
<li>升级axios到最新版本0.24.0</li>
<li>升级dart-sass到版本1.32.13</li>
<li>升级core-js到最新版本3.19.1</li>
<li>升级jsencrypt到最新版本3.2.1</li>
<li>升级js-cookie到最新版本3.0.1</li>
<li>升级file-saver到最新版本2.0.5</li>
<li>升级sass-loader到最新版本10.1.1</li>
<li>升级element-ui到最新版本2.15.6</li>
<li>新增sendGet无参请求方法</li>
<li>禁用el-tag组件的渐变动画</li>
<li>代码生成点击预览重置激活tab</li>
<li>AjaxResult重写put方法以方便链式调用</li>
<li>优化登录/验证码请求headers不设置token</li>
<li>优化用户个人信息接口防止修改用户名</li>
<li>优化Cron表达式生成器关闭时销毁避免缓存</li>
<li>优化注册成功提示消息类型success</li>
<li>优化aop语法使用spring自动注入注解</li>
<li>优化记录登录信息移除不必要的修改</li>
<li>优化mybatis全局默认的执行器</li>
<li>优化Excel导入图片可能出现的异常</li>
<li>修复代码生成模板主子表删除缺少事务</li>
<li>修复日志记录可能出现的转换异常</li>
<li>修复代码生成复选框字典遗漏问题</li>
<li>修复关闭xss功能导致可重复读RepeatableFilter失效</li>
<li>修复字符串无法被反转义问题</li>
<li>修复后端主子表代码模板方法名生成错误问题</li>
<li>修复xss过滤后格式出现的异常</li>
<li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>
<li>其他细节优化</li>
</ol>
</el-collapse-item>
<el-collapse-item title="v3.7.0 - 2021-09-13">
<ol>
<li>参数管理支持配置验证码开关</li>
@@ -665,7 +751,7 @@
</template>
<script setup name="Index">
const version = ref('3.7.0')
const version = ref('3.8.1')
function goTarget(url) {
window.open(url, '__blank')

View File

@@ -210,7 +210,7 @@
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="错误策略" prop="misfirePolicy">
<el-form-item label="执行策略" prop="misfirePolicy">
<el-radio-group v-model="form.misfirePolicy" size="small">
<el-radio-button label="1">立即执行</el-radio-button>
<el-radio-button label="2">执行一次</el-radio-button>
@@ -348,7 +348,7 @@ function getList() {
}
/** 任务组名字典翻译 */
function jobGroupFormat(row, column) {
return proxy.selectDictLabel(sys_job_group, row.jobGroup);
return proxy.selectDictLabel(sys_job_group.value, row.jobGroup);
}
/** 取消按钮 */
function cancel() {

View File

@@ -99,7 +99,6 @@ function resetQuery() {
}
/** 强退按钮操作 */
function handleForceLogout(row) {
const operIds = row.operId || ids.value;
proxy.$modal.confirm('是否确认强退名称为"' + row.userName + '"的用户?').then(function () {
return forceLogout(row.tokenId);
}).then(() => {

View File

@@ -238,7 +238,7 @@ function getList() {
}
/** 操作日志类型字典翻译 */
function typeFormat(row, column) {
return selectDictLabel(sys_oper_type, row.businessType);
return proxy.selectDictLabel(sys_oper_type.value, row.businessType);
}
/** 搜索按钮操作 */
function handleQuery() {

View File

@@ -127,7 +127,7 @@
</el-form-item>
</el-col>
<el-col :span="24" v-if="form.menuType != 'F'">
<el-form-item label="菜单图标">
<el-form-item label="菜单图标" prop="icon">
<el-popover
placement="bottom-start"
:width="540"

View File

@@ -9,7 +9,7 @@
</el-form-item>
</el-col>
<el-col :span="8" :offset="2">
<el-form-item label="登录账号" prop="phonenumber">
<el-form-item label="登录账号" prop="userName">
<el-input v-model="form.userName" disabled />
</el-form-item>
</el-col>

View File

@@ -451,7 +451,7 @@ function getList() {
/** 节点单击事件 */
function handleNodeClick(data) {
queryParams.value.deptId = data.id;
getList();
handleQuery();
};
/** 搜索按钮操作 */
function handleQuery() {
@@ -548,7 +548,7 @@ const handleFileSuccess = (response, file, fileList) => {
upload.open = false;
upload.isUploading = false;
proxy.$refs["uploadRef"].clearFiles();
proxy.$alert(response.msg, "导入结果", { dangerouslyUseHTMLString: true });
proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
getList();
};
/** 提交上传文件 */

View File

@@ -158,7 +158,7 @@
@pagination="getList"
/>
<!-- 预览界面 -->
<el-dialog :title="preview.title" v-model="preview.open" width="80%" top="5vh" append-to-body class="scrollbar">
<el-dialog :title="preview.title" v-model="preview.open" width="80%" top="5vh" append-to-body custom-class="scrollbar">
<el-tabs v-model="preview.activeName">
<el-tab-pane
v-for="(value, key) in preview.data"
@@ -166,7 +166,7 @@
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
:key="key"
>
<pre><code class="hljs" v-html="value"></code></pre>
<pre>{{ value }}</pre>
</el-tab-pane>
</el-tabs>
</el-dialog>

View File

@@ -21,6 +21,7 @@ export default defineConfig(({ mode, command }) => {
// vite 相关配置
server: {
port: 80,
host: true,
open: true,
proxy: {
// https://cn.vitejs.dev/config/#server-proxy

View File

@@ -5,6 +5,7 @@ export default function createCompression(env) {
const compressList = VITE_BUILD_COMPRESS.split(',')
const plugin = []
if (compressList.includes('gzip')) {
// http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
plugin.push(
compression({
ext: '.gz',