forked from ruoyi/RuoYi-Vue3
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9d754c886 | ||
|
|
13a5bf8585 | ||
|
|
fa97ed9e2c | ||
|
|
cda383534e | ||
|
|
61161cdd69 | ||
|
|
ec4170a4f1 | ||
|
|
fece6740a4 | ||
|
|
bb3f449388 | ||
|
|
3d7b36932e | ||
|
|
03a06c3415 | ||
|
|
6cf9c3ffb6 | ||
|
|
5621ea4a29 | ||
|
|
a2aa467030 | ||
|
|
f5f717d0d4 | ||
|
|
fc372111ae | ||
|
|
ce3c9ef16d | ||
|
|
f13899808f | ||
|
|
475e27f4a6 | ||
|
|
f3b1470a5c | ||
|
|
d366a5046d | ||
|
|
02b0bd0ec6 | ||
|
|
463011bb66 | ||
|
|
e170ac272d | ||
|
|
c246d868a9 | ||
|
|
b6744f8f99 | ||
|
|
674a483ae7 | ||
|
|
0c103e53b9 | ||
|
|
6db6cecb17 | ||
|
|
6222fb6614 | ||
|
|
03fe9f42d9 | ||
|
|
f8037c23ba | ||
|
|
f2cf400c8b | ||
|
|
25e801e579 | ||
|
|
3ddb5e9b38 |
@@ -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
|
||||
@@ -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
|
||||
17
package.json
17
package.json
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
188
src/components/FileUpload/index.vue
Normal file
188
src/components/FileUpload/index.vue
Normal 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>
|
||||
67
src/components/ImagePreview/index.vue
Normal file
67
src/components/ImagePreview/index.vue
Normal 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>
|
||||
197
src/components/ImageUpload/index.vue
Normal file
197
src/components/ImageUpload/index.vue
Normal 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>
|
||||
@@ -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"
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 "";
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
/** 提交上传文件 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user