forked from aixan/RuoYi-Vue3-Template
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b3157d905 | ||
|
|
73117214d0 | ||
|
|
489ebdf4b1 | ||
|
|
1def54572a | ||
|
|
163d6727b4 | ||
|
|
ade1d01e31 | ||
|
|
184ccbde43 | ||
|
|
a08c28e509 | ||
|
|
56563b4f8e | ||
|
|
1c8473a5da | ||
|
|
9293d19c26 | ||
|
|
ab3df692b9 | ||
|
|
1e5ac4c55f | ||
|
|
403e86b7f3 | ||
|
|
44ad220cdd | ||
|
|
6f359c1534 | ||
|
|
409457a4a4 | ||
|
|
213b67d666 | ||
|
|
ec6b87c3c4 | ||
|
|
301dd0ec69 | ||
|
|
a48bd04b26 | ||
|
|
7d77822311 | ||
|
|
49a6f4d362 | ||
|
|
719e0853fa | ||
|
|
1e08687175 | ||
|
|
d7379d8469 | ||
|
|
a49e6c4d7c | ||
|
|
5c4c90a27c | ||
|
|
8c4ad74120 | ||
|
|
4e347e9853 | ||
|
|
306137bba1 | ||
|
|
5bd1502433 | ||
|
|
17950a3254 | ||
|
|
cc844b6b7c | ||
|
|
b2294592f9 | ||
|
|
d7af461d2c | ||
|
|
75cfe2f8f7 | ||
|
|
6b36385fa5 | ||
|
|
f149f8a64b | ||
|
|
59c114b6c0 | ||
|
|
299e69968e | ||
|
|
1baa04f459 | ||
|
|
6b6ad94650 | ||
|
|
f6a8e02d37 | ||
|
|
df76a7cd71 |
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.1</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.3</h1>
|
||||
<h4 align="center">基于SpringBoot+Vue3前后端分离的Java快速开发框架</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.1-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.3-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
||||
</p>
|
||||
|
||||
@@ -106,4 +106,4 @@ yarn dev
|
||||
|
||||
## 若依前后端分离交流群
|
||||
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) 点击按钮入群。
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=njiWDmkj) 点击按钮入群。
|
||||
39
package.json
39
package.json
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "ruoyi",
|
||||
"version": "3.8.2",
|
||||
"version": "3.8.3",
|
||||
"description": "若依管理系统",
|
||||
"author": "若依",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build:prod": "vite build",
|
||||
"build:prod": "vite build",
|
||||
"build:stage": "vite build --mode staging",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
@@ -15,28 +15,29 @@
|
||||
"url": "https://gitee.com/y_project/RuoYi-Vue.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@element-plus/icons-vue": "0.2.6",
|
||||
"axios": "0.24.0",
|
||||
"echarts": "5.2.2",
|
||||
"element-plus": "2.0.1",
|
||||
"@element-plus/icons-vue": "1.1.4",
|
||||
"@vueuse/core": "8.5.0",
|
||||
"axios": "0.26.1",
|
||||
"echarts": "5.3.2",
|
||||
"element-plus": "2.1.8",
|
||||
"file-saver": "2.0.5",
|
||||
"fuse.js": "6.4.6",
|
||||
"fuse.js": "6.5.3",
|
||||
"js-cookie": "3.0.1",
|
||||
"jsencrypt": "3.2.1",
|
||||
"nprogress": "0.2.0",
|
||||
"vue": "3.2.26",
|
||||
"vue-cropper": "1.0.2",
|
||||
"vue-router": "4.0.12",
|
||||
"vuex": "4.0.2"
|
||||
"pinia": "2.0.14",
|
||||
"vue": "3.2.31",
|
||||
"vue-cropper": "1.0.3",
|
||||
"vue-router": "4.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "1.9.4",
|
||||
"@vue/compiler-sfc": "3.2.22",
|
||||
"sass": "1.45.0",
|
||||
"unplugin-auto-import": "0.5.3",
|
||||
"vite": "2.6.14",
|
||||
"vite-plugin-compression": "0.3.6",
|
||||
"vite-plugin-svg-icons": "1.0.5",
|
||||
"vite-plugin-vue-setup-extend": "0.1.0"
|
||||
"@vitejs/plugin-vue": "2.3.3",
|
||||
"@vue/compiler-sfc": "3.2.36",
|
||||
"sass": "1.52.1",
|
||||
"unplugin-auto-import": "0.8.5",
|
||||
"vite": "2.9.9",
|
||||
"vite-plugin-compression": "0.5.1",
|
||||
"vite-plugin-svg-icons": "2.0.1",
|
||||
"vite-plugin-vue-setup-extend": "0.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,52 @@ export function getCache() {
|
||||
url: '/monitor/cache',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查询缓存名称列表
|
||||
export function listCacheName() {
|
||||
return request({
|
||||
url: '/monitor/cache/getNames',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询缓存键名列表
|
||||
export function listCacheKey(cacheName) {
|
||||
return request({
|
||||
url: '/monitor/cache/getKeys/' + cacheName,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 查询缓存内容
|
||||
export function getCacheValue(cacheName, cacheKey) {
|
||||
return request({
|
||||
url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 清理指定名称缓存
|
||||
export function clearCacheName(cacheName) {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheName/' + cacheName,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 清理指定键名缓存
|
||||
export function clearCacheKey(cacheKey) {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheKey/' + cacheKey,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 清理全部缓存
|
||||
export function clearCacheAll() {
|
||||
return request({
|
||||
url: '/monitor/cache/clearCacheAll',
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
2
src/assets/icons/svg/redis-list.svg
Normal file
2
src/assets/icons/svg/redis-list.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1656035183065" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3395" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
|
||||
</style></defs><path d="M958.88 730.06H65.12c-18.28 0-33.12-14.82-33.12-33.12V68.91c0-18.29 14.83-33.12 33.12-33.12h893.77c18.28 0 33.12 14.82 33.12 33.12v628.03c-0.01 18.3-14.84 33.12-33.13 33.12zM98.23 663.83h827.53v-561.8H98.23v561.8z" p-id="3396"></path><path d="M512 954.55c-18.28 0-33.12-14.82-33.12-33.12V733.92c0-18.29 14.83-33.12 33.12-33.12s33.12 14.82 33.12 33.12v187.51c0 18.3-14.84 33.12-33.12 33.12z" p-id="3397"></path><path d="M762.01 988.21H261.99c-18.28 0-33.12-14.82-33.12-33.12 0-18.29 14.83-33.12 33.12-33.12h500.03c18.28 0 33.12 14.82 33.12 33.12-0.01 18.29-14.84 33.12-33.13 33.12zM514.74 578.55c-21.63 0-43.31-3.87-64.21-11.65-45.95-17.13-82.49-51.13-102.86-95.74-5.07-11.08-0.19-24.19 10.89-29.26 11.08-5.09 24.19-0.18 29.26 10.91 15.5 33.88 43.25 59.7 78.14 72.71 34.93 12.99 72.79 11.64 106.66-3.85 33.22-15.17 58.8-42.26 72.03-76.3 4.42-11.37 17.21-17.01 28.57-12.58 11.36 4.42 16.99 17.22 12.57 28.58-17.42 44.82-51.1 80.5-94.82 100.47-24.34 11.12-50.25 16.71-76.23 16.71z" p-id="3398"></path><path d="M325.27 528.78c-1.66 0-3.34-0.18-5.02-0.57-11.88-2.77-19.28-14.63-16.49-26.51l18.84-81c1.34-5.82 5-10.84 10.13-13.92 5.09-3.09 11.3-3.96 17.03-2.41l80.51 21.43c11.79 3.14 18.8 15.23 15.67 27.02-3.15 11.79-15.42 18.75-27.02 15.65l-58.49-15.57-13.69 58.81c-2.37 10.2-11.45 17.07-21.47 17.07zM360.8 351.01c-2.65 0-5.37-0.49-8-1.51-11.36-4.41-16.99-17.21-12.59-28.57 17.4-44.79 51.06-80.47 94.8-100.48 92.15-42.06 201.25-1.39 243.31 90.68 5.07 11.08 0.19 24.19-10.89 29.26-11.13 5.07-24.19 0.17-29.26-10.91-31.97-69.91-114.9-100.82-184.79-68.86-33.22 15.19-58.8 42.28-71.99 76.29-3.41 8.74-11.75 14.1-20.59 14.1z" p-id="3399"></path><path d="M684.68 376.74c-1.47 0-2.95-0.15-4.42-0.44l-81.61-16.68c-11.94-2.45-19.64-14.11-17.21-26.06 2.44-11.96 14.1-19.64 26.04-17.22l59.29 12.12 10.23-59.5c2.05-12 13.52-20.19 25.48-18.01 12.03 2.06 20.09 13.48 18.02 25.5l-14.08 81.96a22.089 22.089 0 0 1-9.29 14.49c-3.7 2.51-8.03 3.84-12.45 3.84z" p-id="3400"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
@@ -268,7 +268,7 @@
|
||||
background: #42b983!important;
|
||||
}
|
||||
|
||||
/* 表格右侧工具栏样式 */
|
||||
.top-right-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.el-menu-item .el-menu-tooltip__trigger {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
// menu hover
|
||||
.sub-menu-title-noDropdown,
|
||||
.el-sub-menu__title {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
v-if="item.elTagType == 'default' || item.elTagType == ''"
|
||||
:key="item.value"
|
||||
:index="index"
|
||||
:class="item.elTagType"
|
||||
:class="item.elTagClass"
|
||||
>{{ item.label }}</span>
|
||||
<el-tag
|
||||
v-else
|
||||
@@ -14,7 +14,7 @@
|
||||
:key="item.value + ''"
|
||||
:index="index"
|
||||
:type="item.elTagType === 'primary' ? '' : item.elTagType"
|
||||
:class="item.elTagType"
|
||||
:class="item.elTagClass"
|
||||
>{{ item.label }}</el-tag>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -16,15 +16,14 @@
|
||||
>
|
||||
<!-- 上传按钮 -->
|
||||
<el-button 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>
|
||||
|
||||
<!-- 上传提示 -->
|
||||
<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>
|
||||
<!-- 文件列表 -->
|
||||
<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">
|
||||
@@ -95,7 +94,7 @@ watch(() => props.modelValue, val => {
|
||||
fileList.value = [];
|
||||
return [];
|
||||
}
|
||||
});
|
||||
},{ deep: true, immediate: true });
|
||||
|
||||
// 上传前校检格式和大小
|
||||
function handleBeforeUpload(file) {
|
||||
@@ -142,7 +141,7 @@ function handleUploadError(err) {
|
||||
function handleUploadSuccess(res, file) {
|
||||
uploadList.value.push({ name: res.fileName, url: res.fileName });
|
||||
if (uploadList.value.length === number.value) {
|
||||
fileList.value = fileList.value.concat(uploadList.value);
|
||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
@@ -170,7 +169,9 @@ function listToString(list, separator) {
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
for (let i in list) {
|
||||
strs += list[i].url + separator;
|
||||
if(undefined !== list[i].url) {
|
||||
strs += list[i].url + separator;
|
||||
}
|
||||
}
|
||||
return strs != '' ? strs.substr(0, strs.length - 1) : '';
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
import Fuse from 'fuse.js'
|
||||
import { getNormalPath } from '@/utils/ruoyi'
|
||||
import { isHttp } from '@/utils/validate'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
const search = ref('');
|
||||
const options = ref([]);
|
||||
@@ -28,9 +29,8 @@ const searchPool = ref([]);
|
||||
const show = ref(false);
|
||||
const fuse = ref(undefined);
|
||||
const headerSearchSelectRef = ref(null);
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
const routes = computed(() => store.getters.permission_routes);
|
||||
const routes = computed(() => usePermissionStore().routes);
|
||||
|
||||
function click() {
|
||||
show.value = !show.value
|
||||
|
||||
@@ -105,22 +105,18 @@ watch(() => props.modelValue, val => {
|
||||
fileList.value = [];
|
||||
return [];
|
||||
}
|
||||
});
|
||||
},{ deep: true, immediate: true });
|
||||
|
||||
// 删除图片
|
||||
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));
|
||||
}
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
}
|
||||
|
||||
// 上传成功回调
|
||||
function handleUploadSuccess(res) {
|
||||
uploadList.value.push({ name: res.fileName, url: res.fileName });
|
||||
if (uploadList.value.length === number.value) {
|
||||
fileList.value = fileList.value.concat(uploadList.value);
|
||||
fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
|
||||
uploadList.value = [];
|
||||
number.value = 0;
|
||||
emit("update:modelValue", listToString(fileList.value));
|
||||
@@ -183,7 +179,9 @@ function listToString(list, separator) {
|
||||
let strs = "";
|
||||
separator = separator || ",";
|
||||
for (let i in list) {
|
||||
strs += list[i].url.replace(baseUrl, "") + separator;
|
||||
if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) {
|
||||
strs += list[i].url.replace(baseUrl, "") + separator;
|
||||
}
|
||||
}
|
||||
return strs != "" ? strs.substr(0, strs.length - 1) : "";
|
||||
}
|
||||
@@ -192,15 +190,6 @@ function listToString(list, separator) {
|
||||
<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);
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@@ -16,36 +16,24 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessage } from 'element-plus'
|
||||
import useAppStore from "@/store/modules/app";
|
||||
|
||||
const store = useStore();
|
||||
const size = computed(() => store.getters.size);
|
||||
const appStore = useAppStore();
|
||||
const size = computed(() => appStore.size);
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const {proxy} = getCurrentInstance();
|
||||
const { proxy } = getCurrentInstance();
|
||||
const sizeOptions = ref([
|
||||
{ label: '较大', value: 'large' },
|
||||
{ label: '默认', value: 'default' },
|
||||
{ label: '稍小', value: 'small' },
|
||||
])
|
||||
{ label: "较大", value: "large" },
|
||||
{ label: "默认", value: "default" },
|
||||
{ label: "稍小", value: "small" },
|
||||
]);
|
||||
|
||||
function refreshView() {
|
||||
// In order to make the cached page re-rendered
|
||||
store.dispatch('tagsView/delAllCachedViews', route)
|
||||
|
||||
const { fullPath } = route
|
||||
|
||||
nextTick(() => {
|
||||
router.replace({
|
||||
path: '/redirect' + fullPath
|
||||
})
|
||||
})
|
||||
}
|
||||
function handleSetSize(size) {
|
||||
proxy.$modal.loading("正在设置布局大小,请稍候...");
|
||||
store.dispatch('app/setSize', size)
|
||||
setTimeout("window.location.reload()", 1000)
|
||||
};
|
||||
appStore.setSize(size);
|
||||
setTimeout("window.location.reload()", 1000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
<script setup>
|
||||
import { constantRoutes } from "@/router"
|
||||
import { isHttp } from '@/utils/validate'
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
// 顶部栏初始数
|
||||
const visibleNumber = ref(null);
|
||||
@@ -38,14 +41,16 @@ const currentIndex = ref(null);
|
||||
// 隐藏侧边栏路由
|
||||
const hideList = ['/index', '/user/profile'];
|
||||
|
||||
const store = useStore();
|
||||
const appStore = useAppStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
// 主题颜色
|
||||
const theme = computed(() => store.state.settings.theme);
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
// 所有的路由信息
|
||||
const routers = computed(() => store.state.permission.topbarRouters);
|
||||
const routers = computed(() => permissionStore.topbarRouters);
|
||||
|
||||
// 顶部显示菜单
|
||||
const topMenus = computed(() => {
|
||||
@@ -91,10 +96,10 @@ const activeMenu = computed(() => {
|
||||
if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
|
||||
const tmpPath = path.substring(1, path.length);
|
||||
activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
|
||||
store.dispatch('app/toggleSideBarHide', false);
|
||||
appStore.toggleSideBarHide(false);
|
||||
} else if(!route.children) {
|
||||
activePath = path;
|
||||
store.dispatch('app/toggleSideBarHide', true);
|
||||
appStore.toggleSideBarHide(true);
|
||||
}
|
||||
activeRoutes(activePath);
|
||||
return activePath;
|
||||
@@ -114,11 +119,11 @@ function handleSelect(key, keyPath) {
|
||||
} else if (!route || !route.children) {
|
||||
// 没有子路由路径内部打开
|
||||
router.push({ path: key });
|
||||
store.dispatch('app/toggleSideBarHide', true);
|
||||
appStore.toggleSideBarHide(true);
|
||||
} else {
|
||||
// 显示左侧联动菜单
|
||||
activeRoutes(key);
|
||||
store.dispatch('app/toggleSideBarHide', false);
|
||||
appStore.toggleSideBarHide(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +137,7 @@ function activeRoutes(key) {
|
||||
});
|
||||
}
|
||||
if(routes.length > 0) {
|
||||
store.commit("SET_SIDEBAR_ROUTERS", routes);
|
||||
permissionStore.setSidebarRouters(routes);
|
||||
}
|
||||
return routes;
|
||||
}
|
||||
|
||||
66
src/directive/common/copyText.js
Normal file
66
src/directive/common/copyText.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* v-copyText 复制文本内容
|
||||
* Copyright (c) 2022 ruoyi
|
||||
*/
|
||||
|
||||
export default {
|
||||
beforeMount(el, { value, arg }) {
|
||||
if (arg === "callback") {
|
||||
el.$copyCallback = value;
|
||||
} else {
|
||||
el.$copyValue = value;
|
||||
const handler = () => {
|
||||
copyTextToClipboard(el.$copyValue);
|
||||
if (el.$copyCallback) {
|
||||
el.$copyCallback(el.$copyValue);
|
||||
}
|
||||
};
|
||||
el.addEventListener("click", handler);
|
||||
el.$destroyCopy = () => el.removeEventListener("click", handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function copyTextToClipboard(input, { target = document.body } = {}) {
|
||||
const element = document.createElement('textarea');
|
||||
const previouslyFocusedElement = document.activeElement;
|
||||
|
||||
element.value = input;
|
||||
|
||||
// Prevent keyboard from showing on mobile
|
||||
element.setAttribute('readonly', '');
|
||||
|
||||
element.style.contain = 'strict';
|
||||
element.style.position = 'absolute';
|
||||
element.style.left = '-9999px';
|
||||
element.style.fontSize = '12pt'; // Prevent zooming on iOS
|
||||
|
||||
const selection = document.getSelection();
|
||||
const originalRange = selection.rangeCount > 0 && selection.getRangeAt(0);
|
||||
|
||||
target.append(element);
|
||||
element.select();
|
||||
|
||||
// Explicit selection workaround for iOS
|
||||
element.selectionStart = 0;
|
||||
element.selectionEnd = input.length;
|
||||
|
||||
let isSuccess = false;
|
||||
try {
|
||||
isSuccess = document.execCommand('copy');
|
||||
} catch { }
|
||||
|
||||
element.remove();
|
||||
|
||||
if (originalRange) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(originalRange);
|
||||
}
|
||||
|
||||
// Get the focus back on the previously focused element, if any
|
||||
if (previouslyFocusedElement) {
|
||||
previouslyFocusedElement.focus();
|
||||
}
|
||||
|
||||
return isSuccess;
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import hasRole from './permission/hasRole'
|
||||
import hasPermi from './permission/hasPermi'
|
||||
import copyText from './common/copyText'
|
||||
|
||||
export default function directive(app){
|
||||
app.directive('hasRole', hasRole)
|
||||
app.directive('hasPermi', hasPermi)
|
||||
app.directive('copyText', copyText)
|
||||
}
|
||||
@@ -3,13 +3,13 @@
|
||||
* Copyright (c) 2019 ruoyi
|
||||
*/
|
||||
|
||||
import store from '@/store'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
export default {
|
||||
mounted(el, binding, vnode) {
|
||||
const { value } = binding
|
||||
const all_permission = "*:*:*";
|
||||
const permissions = store.getters && store.getters.permissions
|
||||
const permissions = useUserStore().permissions
|
||||
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissionFlag = value
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
* Copyright (c) 2019 ruoyi
|
||||
*/
|
||||
|
||||
import store from '@/store'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
export default {
|
||||
mounted(el, binding, vnode) {
|
||||
const { value } = binding
|
||||
const super_admin = "admin";
|
||||
const roles = store.getters && store.getters.roles
|
||||
const roles = useUserStore().roles
|
||||
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const roleFlag = value
|
||||
|
||||
@@ -11,11 +11,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
let store = useStore()
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
const route = useRoute()
|
||||
store.dispatch('tagsView/addCachedView', route)
|
||||
tagsViewStore.addCachedView(route)
|
||||
const cachedViews = computed(() => {
|
||||
return store.state.tagsView.cachedViews
|
||||
return tagsViewStore.cachedViews
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger id="hamburger-container" :is-active="getters.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!$store.state.settings.topNav" />
|
||||
<top-nav id="topmenu-container" class="topmenu-container" v-if="$store.state.settings.topNav" />
|
||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
|
||||
<breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!settingsStore.topNav" />
|
||||
<top-nav id="topmenu-container" class="topmenu-container" v-if="settingsStore.topNav" />
|
||||
|
||||
<div class="right-menu">
|
||||
<template v-if="getters.device !== 'mobile'">
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
<header-search id="header-search" class="right-menu-item" />
|
||||
|
||||
<el-tooltip content="源码地址" effect="dark" placement="bottom">
|
||||
@@ -25,7 +25,7 @@
|
||||
<div class="avatar-container">
|
||||
<el-dropdown @command="handleCommand" class="right-menu-item hover-effect" trigger="click">
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="getters.avatar" class="user-avatar" />
|
||||
<img :src="userStore.avatar" class="user-avatar" />
|
||||
<el-icon><caret-bottom /></el-icon>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
@@ -57,12 +57,16 @@ import SizeSelect from '@/components/SizeSelect'
|
||||
import HeaderSearch from '@/components/HeaderSearch'
|
||||
import RuoYiGit from '@/components/RuoYi/Git'
|
||||
import RuoYiDoc from '@/components/RuoYi/Doc'
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
|
||||
const store = useStore();
|
||||
const getters = computed(() => store.getters);
|
||||
const appStore = useAppStore()
|
||||
const userStore = useUserStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
function toggleSideBar() {
|
||||
store.dispatch('app/toggleSideBar')
|
||||
appStore.toggleSideBar()
|
||||
}
|
||||
|
||||
function handleCommand(command) {
|
||||
@@ -84,7 +88,7 @@ function logout() {
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
userStore.logOut().then(() => {
|
||||
location.href = '/index';
|
||||
})
|
||||
}).catch(() => { });
|
||||
|
||||
@@ -84,26 +84,28 @@ import originElementPlus from 'element-plus/theme-chalk/index.css'
|
||||
import axios from 'axios'
|
||||
import { ElLoading, ElMessage } from 'element-plus'
|
||||
import { useDynamicTitle } from '@/utils/dynamicTitle'
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const store = useStore();
|
||||
const appStore = useAppStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
const showSettings = ref(false);
|
||||
const theme = ref(store.state.settings.theme);
|
||||
const sideTheme = ref(store.state.settings.sideTheme);
|
||||
const storeSettings = computed(() => store.state.settings);
|
||||
const theme = ref(settingsStore.theme);
|
||||
const sideTheme = ref(settingsStore.sideTheme);
|
||||
const storeSettings = computed(() => settingsStore);
|
||||
const predefineColors = ref(["#409EFF", "#ff4500", "#ff8c00", "#ffd700", "#90ee90", "#00ced1", "#1e90ff", "#c71585"]);
|
||||
|
||||
/** 是否需要topnav */
|
||||
const topNav = computed({
|
||||
get: () => storeSettings.value.topNav,
|
||||
set: (val) => {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'topNav',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'topNav', value: val })
|
||||
if (!val) {
|
||||
store.dispatch('app/toggleSideBarHide', false);
|
||||
store.commit("SET_SIDEBAR_ROUTERS", store.state.permission.defaultRoutes);
|
||||
appStore.toggleSideBarHide(false);
|
||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -111,57 +113,39 @@ const topNav = computed({
|
||||
const tagsView = computed({
|
||||
get: () => storeSettings.value.tagsView,
|
||||
set: (val) => {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'tagsView',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'tagsView', value: val })
|
||||
}
|
||||
})
|
||||
/**是否需要固定头部 */
|
||||
const fixedHeader = computed({
|
||||
get: () => storeSettings.value.fixedHeader,
|
||||
set: (val) => {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'fixedHeader',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'fixedHeader', value: val })
|
||||
}
|
||||
})
|
||||
/**是否需要侧边栏的logo */
|
||||
const sidebarLogo = computed({
|
||||
get: () => storeSettings.value.sidebarLogo,
|
||||
set: (val) => {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'sidebarLogo',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'sidebarLogo', value: val })
|
||||
}
|
||||
})
|
||||
/**是否需要侧边栏的动态网页的title */
|
||||
const dynamicTitle = computed({
|
||||
get: () => storeSettings.value.dynamicTitle,
|
||||
set: (val) => {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'dynamicTitle',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'dynamicTitle', value: val })
|
||||
// 动态设置网页标题
|
||||
useDynamicTitle()
|
||||
}
|
||||
})
|
||||
|
||||
function themeChange(val) {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'theme',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'theme', value: val })
|
||||
theme.value = val;
|
||||
}
|
||||
function handleTheme(val) {
|
||||
store.dispatch('settings/changeSetting', {
|
||||
key: 'sideTheme',
|
||||
value: val
|
||||
})
|
||||
settingsStore.changeSetting({ key: 'sideTheme', value: val })
|
||||
sideTheme.value = val;
|
||||
}
|
||||
function saveSetting() {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
<script setup>
|
||||
import variables from '@/assets/styles/variables.module.scss'
|
||||
import logo from '@/assets/logo/logo.png'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
|
||||
defineProps({
|
||||
collapse: {
|
||||
@@ -25,8 +26,8 @@ defineProps({
|
||||
})
|
||||
|
||||
const title = ref('若依管理系统');
|
||||
const store = useStore();
|
||||
const sideTheme = computed(() => store.state.settings.sideTheme);
|
||||
const settingsStore = useSettingsStore();
|
||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -27,15 +27,20 @@
|
||||
import Logo from './Logo'
|
||||
import SidebarItem from './SidebarItem'
|
||||
import variables from '@/assets/styles/variables.module.scss'
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
const appStore = useAppStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const sidebarRouters = computed(() => store.getters.sidebarRouters);
|
||||
const showLogo = computed(() => store.state.settings.sidebarLogo);
|
||||
const sideTheme = computed(() => store.state.settings.sideTheme);
|
||||
const theme = computed(() => store.state.settings.theme);
|
||||
const isCollapse = computed(() => !store.state.app.sidebar.opened);
|
||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters);
|
||||
const showLogo = computed(() => settingsStore.sidebarLogo);
|
||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
const isCollapse = computed(() => !appStore.sidebar.opened);
|
||||
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
|
||||
const tagAndTagSpacing = ref(4);
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
@@ -32,8 +34,8 @@ const emitScroll = () => {
|
||||
emits('scroll')
|
||||
}
|
||||
|
||||
const store = useStore();
|
||||
const visitedViews = computed(() => store.state.tagsView.visitedViews);
|
||||
const tagsViewStore = useTagsViewStore()
|
||||
const visitedViews = computed(() => tagsViewStore.visitedViews);
|
||||
|
||||
function moveToTarget(currentTag) {
|
||||
const $container = proxy.$refs.scrollContainer.$el
|
||||
|
||||
@@ -44,6 +44,9 @@
|
||||
<script setup>
|
||||
import ScrollPane from './ScrollPane'
|
||||
import { getNormalPath } from '@/utils/ruoyi'
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
const visible = ref(false);
|
||||
const top = ref(0);
|
||||
@@ -53,13 +56,12 @@ const affixTags = ref([]);
|
||||
const scrollPaneRef = ref(null);
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const store = useStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
const visitedViews = computed(() => store.state.tagsView.visitedViews);
|
||||
const routes = computed(() => store.state.permission.routes);
|
||||
const theme = computed(() => store.state.settings.theme);
|
||||
const visitedViews = computed(() => useTagsViewStore().visitedViews);
|
||||
const routes = computed(() => usePermissionStore().routes);
|
||||
const theme = computed(() => useSettingsStore().theme);
|
||||
|
||||
watch(route, () => {
|
||||
addTags()
|
||||
@@ -131,14 +133,14 @@ function initTags() {
|
||||
for (const tag of res) {
|
||||
// Must have tag name
|
||||
if (tag.name) {
|
||||
store.dispatch('tagsView/addVisitedView', tag)
|
||||
useTagsViewStore().addVisitedView(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
function addTags() {
|
||||
const { name } = route
|
||||
if (name) {
|
||||
store.dispatch('tagsView/addView', route)
|
||||
useTagsViewStore().addView(route)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -149,7 +151,7 @@ function moveToCurrentTag() {
|
||||
scrollPaneRef.value.moveToTarget(r);
|
||||
// when query is different then update
|
||||
if (r.fullPath !== route.fullPath) {
|
||||
store.dispatch('tagsView/updateVisitedView', route)
|
||||
useTagsViewStore().updateVisitedView(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,16 @@ import Sidebar from './components/Sidebar/index.vue'
|
||||
import { AppMain, Navbar, Settings, TagsView } from './components'
|
||||
import defaultSettings from '@/settings'
|
||||
|
||||
const store = useStore();
|
||||
const theme = computed(() => store.state.settings.theme);
|
||||
const sideTheme = computed(() => store.state.settings.sideTheme);
|
||||
const sidebar = computed(() => store.state.app.sidebar);
|
||||
const device = computed(() => store.state.app.device);
|
||||
const needTagsView = computed(() => store.state.settings.tagsView);
|
||||
const fixedHeader = computed(() => store.state.settings.fixedHeader);
|
||||
import useAppStore from '@/store/modules/app'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
|
||||
const settingsStore = useSettingsStore()
|
||||
const theme = computed(() => settingsStore.theme);
|
||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
const sidebar = computed(() => useAppStore().sidebar);
|
||||
const device = computed(() => useAppStore().device);
|
||||
const needTagsView = computed(() => settingsStore.tagsView);
|
||||
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
||||
|
||||
const classObj = computed(() => ({
|
||||
hideSidebar: !sidebar.value.opened,
|
||||
@@ -39,18 +42,18 @@ const WIDTH = 992; // refer to Bootstrap's responsive design
|
||||
|
||||
watchEffect(() => {
|
||||
if (device.value === 'mobile' && sidebar.value.opened) {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
useAppStore().closeSideBar({ withoutAnimation: false })
|
||||
}
|
||||
if (width.value - 1 < WIDTH) {
|
||||
store.dispatch('app/toggleDevice', 'mobile')
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: true })
|
||||
useAppStore().toggleDevice('mobile')
|
||||
useAppStore().closeSideBar({ withoutAnimation: true })
|
||||
} else {
|
||||
store.dispatch('app/toggleDevice', 'desktop')
|
||||
useAppStore().toggleDevice('desktop')
|
||||
}
|
||||
})
|
||||
|
||||
function handleClickOutside() {
|
||||
store.dispatch('app/closeSideBar', { withoutAnimation: false })
|
||||
useAppStore().closeSideBar({ withoutAnimation: false })
|
||||
}
|
||||
|
||||
const settingRef = ref(null);
|
||||
|
||||
@@ -25,7 +25,7 @@ import elementIcons from '@/components/SvgIcon/svgicon'
|
||||
import './permission' // permission control
|
||||
|
||||
import { useDict } from '@/utils/dict'
|
||||
import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel } from '@/utils/ruoyi'
|
||||
import { parseTime, resetForm, addDateRange, handleTree, selectDictLabel, selectDictLabels } from '@/utils/ruoyi'
|
||||
|
||||
// 分页组件
|
||||
import Pagination from '@/components/Pagination'
|
||||
@@ -52,6 +52,7 @@ app.config.globalProperties.resetForm = resetForm
|
||||
app.config.globalProperties.handleTree = handleTree
|
||||
app.config.globalProperties.addDateRange = addDateRange
|
||||
app.config.globalProperties.selectDictLabel = selectDictLabel
|
||||
app.config.globalProperties.selectDictLabels = selectDictLabels
|
||||
|
||||
// 全局组件挂载
|
||||
app.component('DictTag', DictTag)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import NProgress from 'nprogress'
|
||||
import 'nprogress/nprogress.css'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { isHttp } from '@/utils/validate'
|
||||
import { isRelogin } from '@/utils/request'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
import usePermissionStore from '@/store/modules/permission'
|
||||
|
||||
NProgress.configure({ showSpinner: false });
|
||||
|
||||
@@ -14,18 +16,18 @@ const whiteList = ['/login', '/auth-redirect', '/bind', '/register'];
|
||||
router.beforeEach((to, from, next) => {
|
||||
NProgress.start()
|
||||
if (getToken()) {
|
||||
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
|
||||
to.meta.title && useSettingsStore().setTitle(to.meta.title)
|
||||
/* has token*/
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' })
|
||||
NProgress.done()
|
||||
} else {
|
||||
if (store.getters.roles.length === 0) {
|
||||
if (useUserStore().roles.length === 0) {
|
||||
isRelogin.show = true
|
||||
// 判断当前用户是否已拉取完user_info信息
|
||||
store.dispatch('GetInfo').then(() => {
|
||||
useUserStore().getInfo().then(() => {
|
||||
isRelogin.show = false
|
||||
store.dispatch('GenerateRoutes').then(accessRoutes => {
|
||||
usePermissionStore().generateRoutes().then(accessRoutes => {
|
||||
// 根据roles权限生成可访问的路由表
|
||||
accessRoutes.forEach(route => {
|
||||
if (!isHttp(route.path)) {
|
||||
@@ -35,7 +37,7 @@ router.beforeEach((to, from, next) => {
|
||||
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
|
||||
})
|
||||
}).catch(err => {
|
||||
store.dispatch('LogOut').then(() => {
|
||||
useUserStore().logOut().then(() => {
|
||||
ElMessage.error(err)
|
||||
next({ path: '/' })
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import store from '@/store'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
function authPermission(permission) {
|
||||
const all_permission = "*:*:*";
|
||||
const permissions = store.getters && store.getters.permissions
|
||||
const permissions = useUserStore().permissions
|
||||
if (permission && permission.length > 0) {
|
||||
return permissions.some(v => {
|
||||
return all_permission === v || v === permission
|
||||
@@ -14,7 +14,7 @@ function authPermission(permission) {
|
||||
|
||||
function authRole(role) {
|
||||
const super_admin = "admin";
|
||||
const roles = store.getters && store.getters.roles
|
||||
const roles = useUserStore().roles
|
||||
if (role && role.length > 0) {
|
||||
return roles.some(v => {
|
||||
return super_admin === v || v === role
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import store from '@/store'
|
||||
import useTagsViewStore from '@/store/modules/tagsView'
|
||||
import router from '@/router'
|
||||
|
||||
export default {
|
||||
@@ -14,7 +14,7 @@ export default {
|
||||
}
|
||||
});
|
||||
}
|
||||
return store.dispatch('tagsView/delCachedView', obj).then(() => {
|
||||
return useTagsViewStore().delCachedView(obj).then(() => {
|
||||
const { path, query } = obj
|
||||
router.replace({
|
||||
path: '/redirect' + path,
|
||||
@@ -24,7 +24,7 @@ export default {
|
||||
},
|
||||
// 关闭当前tab页签,打开新页签
|
||||
closeOpenPage(obj) {
|
||||
store.dispatch("tagsView/delView", router.currentRoute.value);
|
||||
useTagsViewStore().delView(router.currentRoute.value);
|
||||
if (obj !== undefined) {
|
||||
return router.push(obj);
|
||||
}
|
||||
@@ -32,27 +32,27 @@ export default {
|
||||
// 关闭指定tab页签
|
||||
closePage(obj) {
|
||||
if (obj === undefined) {
|
||||
return store.dispatch('tagsView/delView', router.currentRoute.value).then(({ lastPath }) => {
|
||||
return useTagsViewStore().delView(router.currentRoute.value).then(({ lastPath }) => {
|
||||
return router.push(lastPath || '/index');
|
||||
});
|
||||
}
|
||||
return store.dispatch('tagsView/delView', obj);
|
||||
return useTagsViewStore().delView(obj);
|
||||
},
|
||||
// 关闭所有tab页签
|
||||
closeAllPage() {
|
||||
return store.dispatch('tagsView/delAllViews');
|
||||
return useTagsViewStore().delAllViews();
|
||||
},
|
||||
// 关闭左侧tab页签
|
||||
closeLeftPage(obj) {
|
||||
return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute.value);
|
||||
return useTagsViewStore().delLeftTags(obj || router.currentRoute.value);
|
||||
},
|
||||
// 关闭右侧tab页签
|
||||
closeRightPage(obj) {
|
||||
return store.dispatch('tagsView/delRightTags', obj || router.currentRoute.value);
|
||||
return useTagsViewStore().delRightTags(obj || router.currentRoute.value);
|
||||
},
|
||||
// 关闭其他tab页签
|
||||
closeOtherPage(obj) {
|
||||
return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute.value);
|
||||
return useTagsViewStore().delOthersViews(obj || router.currentRoute.value);
|
||||
},
|
||||
// 打开tab页签
|
||||
openPage(url) {
|
||||
@@ -60,6 +60,6 @@ export default {
|
||||
},
|
||||
// 修改tab页签
|
||||
updatePage(obj) {
|
||||
return store.dispatch('tagsView/updateVisitedView', obj);
|
||||
return useTagsViewStore().updateVisitedView(obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createWebHistory, createRouter } from 'vue-router'
|
||||
/* Layout */
|
||||
import Layout from '@/layout'
|
||||
|
||||
/**
|
||||
@@ -12,6 +13,8 @@ import Layout from '@/layout'
|
||||
* redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
|
||||
* name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题
|
||||
* query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数
|
||||
* roles: ['admin', 'common'] // 访问路由的角色权限
|
||||
* permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限
|
||||
* meta : {
|
||||
noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
|
||||
title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字
|
||||
@@ -80,11 +83,16 @@ export const constantRoutes = [
|
||||
meta: { title: '个人中心', icon: 'user' }
|
||||
}
|
||||
]
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
// 动态路由,基于用户权限动态去加载
|
||||
export const dynamicRoutes = [
|
||||
{
|
||||
path: '/system/user-auth',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['system:user:edit'],
|
||||
children: [
|
||||
{
|
||||
path: 'role/:userId(\\d+)',
|
||||
@@ -98,6 +106,7 @@ export const constantRoutes = [
|
||||
path: '/system/role-auth',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['system:role:edit'],
|
||||
children: [
|
||||
{
|
||||
path: 'user/:roleId(\\d+)',
|
||||
@@ -111,6 +120,7 @@ export const constantRoutes = [
|
||||
path: '/system/dict-data',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['system:dict:list'],
|
||||
children: [
|
||||
{
|
||||
path: 'index/:dictId(\\d+)',
|
||||
@@ -124,6 +134,7 @@ export const constantRoutes = [
|
||||
path: '/monitor/job-log',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['monitor:job:list'],
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
@@ -137,6 +148,7 @@ export const constantRoutes = [
|
||||
path: '/tool/gen-edit',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['tool:gen:edit'],
|
||||
children: [
|
||||
{
|
||||
path: 'index/:tableId(\\d+)',
|
||||
@@ -146,7 +158,7 @@ export const constantRoutes = [
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(),
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
const getters = {
|
||||
sidebar: state => state.app.sidebar,
|
||||
size: state => state.app.size,
|
||||
device: state => state.app.device,
|
||||
visitedViews: state => state.tagsView.visitedViews,
|
||||
cachedViews: state => state.tagsView.cachedViews,
|
||||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name,
|
||||
introduction: state => state.user.introduction,
|
||||
roles: state => state.user.roles,
|
||||
permissions: state => state.user.permissions,
|
||||
permission_routes: state => state.permission.routes,
|
||||
topbarRouters:state => state.permission.topbarRouters,
|
||||
defaultRoutes:state => state.permission.defaultRoutes,
|
||||
sidebarRouters:state => state.permission.sidebarRouters,
|
||||
}
|
||||
export default getters
|
||||
@@ -1,21 +1,3 @@
|
||||
import { createStore } from 'vuex'
|
||||
import app from './modules/app'
|
||||
import user from './modules/user'
|
||||
import tagsView from './modules/tagsView'
|
||||
import permission from './modules/permission'
|
||||
import settings from './modules/settings'
|
||||
import getters from './getters'
|
||||
|
||||
const store = createStore({
|
||||
modules: {
|
||||
app,
|
||||
user,
|
||||
tagsView,
|
||||
permission,
|
||||
settings
|
||||
},
|
||||
getters
|
||||
});
|
||||
|
||||
const store = createPinia()
|
||||
|
||||
export default store
|
||||
@@ -1,66 +1,47 @@
|
||||
import Cookies from 'js-cookie'
|
||||
|
||||
const state = {
|
||||
sidebar: {
|
||||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
|
||||
withoutAnimation: false,
|
||||
hide: false
|
||||
},
|
||||
device: 'desktop',
|
||||
size: Cookies.get('size') || 'default'
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
TOGGLE_SIDEBAR: state => {
|
||||
if (state.sidebar.hide) {
|
||||
return false;
|
||||
const useAppStore = defineStore(
|
||||
'app',
|
||||
{
|
||||
state: () => ({
|
||||
sidebar: {
|
||||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
|
||||
withoutAnimation: false,
|
||||
hide: false
|
||||
},
|
||||
device: 'desktop',
|
||||
size: Cookies.get('size') || 'default'
|
||||
}),
|
||||
actions: {
|
||||
toggleSideBar(withoutAnimation) {
|
||||
if (this.sidebar.hide) {
|
||||
return false;
|
||||
}
|
||||
this.sidebar.opened = !this.sidebar.opened
|
||||
this.sidebar.withoutAnimation = withoutAnimation
|
||||
if (this.sidebar.opened) {
|
||||
Cookies.set('sidebarStatus', 1)
|
||||
} else {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
}
|
||||
},
|
||||
closeSideBar(withoutAnimation) {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
this.sidebar.opened = false
|
||||
this.sidebar.withoutAnimation = withoutAnimation
|
||||
},
|
||||
toggleDevice(device) {
|
||||
this.device = device
|
||||
},
|
||||
setSize(size) {
|
||||
this.size = size;
|
||||
Cookies.set('size', size)
|
||||
},
|
||||
toggleSideBarHide(status) {
|
||||
this.sidebar.hide = status
|
||||
}
|
||||
}
|
||||
state.sidebar.opened = !state.sidebar.opened
|
||||
state.sidebar.withoutAnimation = false
|
||||
if (state.sidebar.opened) {
|
||||
Cookies.set('sidebarStatus', 1)
|
||||
} else {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
}
|
||||
},
|
||||
CLOSE_SIDEBAR: (state, withoutAnimation) => {
|
||||
Cookies.set('sidebarStatus', 0)
|
||||
state.sidebar.opened = false
|
||||
state.sidebar.withoutAnimation = withoutAnimation
|
||||
},
|
||||
TOGGLE_DEVICE: (state, device) => {
|
||||
state.device = device
|
||||
},
|
||||
SET_SIZE: (state, size) => {
|
||||
state.size = size
|
||||
Cookies.set('size', size)
|
||||
},
|
||||
SET_SIDEBAR_HIDE: (state, status) => {
|
||||
state.sidebar.hide = status
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const actions = {
|
||||
toggleSideBar({ commit }) {
|
||||
commit('TOGGLE_SIDEBAR')
|
||||
},
|
||||
closeSideBar({ commit }, { withoutAnimation }) {
|
||||
commit('CLOSE_SIDEBAR', withoutAnimation)
|
||||
},
|
||||
toggleDevice({ commit }, device) {
|
||||
commit('TOGGLE_DEVICE', device)
|
||||
},
|
||||
setSize({ commit }, size) {
|
||||
commit('SET_SIZE', size)
|
||||
},
|
||||
toggleSideBarHide({ commit }, status) {
|
||||
commit('SET_SIDEBAR_HIDE', status)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
export default useAppStore
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { constantRoutes } from '@/router'
|
||||
import auth from '@/plugins/auth'
|
||||
import router, { constantRoutes, dynamicRoutes } from '@/router'
|
||||
import { getRouters } from '@/api/menu'
|
||||
import Layout from '@/layout/index'
|
||||
import ParentView from '@/components/ParentView'
|
||||
@@ -7,51 +8,52 @@ import InnerLink from '@/layout/components/InnerLink'
|
||||
// 匹配views里面所有的.vue文件
|
||||
const modules = import.meta.glob('./../../views/**/*.vue')
|
||||
|
||||
const permission = {
|
||||
state: {
|
||||
routes: [],
|
||||
addRoutes: [],
|
||||
defaultRoutes: [],
|
||||
topbarRouters: [],
|
||||
sidebarRouters: []
|
||||
},
|
||||
mutations: {
|
||||
SET_ROUTES: (state, routes) => {
|
||||
state.addRoutes = routes
|
||||
state.routes = constantRoutes.concat(routes)
|
||||
},
|
||||
SET_DEFAULT_ROUTES: (state, routes) => {
|
||||
state.defaultRoutes = constantRoutes.concat(routes)
|
||||
},
|
||||
SET_TOPBAR_ROUTES: (state, routes) => {
|
||||
state.topbarRouters = routes
|
||||
},
|
||||
SET_SIDEBAR_ROUTERS: (state, routes) => {
|
||||
state.sidebarRouters = routes
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
// 生成路由
|
||||
GenerateRoutes({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
// 向后端请求路由数据
|
||||
getRouters().then(res => {
|
||||
const sdata = JSON.parse(JSON.stringify(res.data))
|
||||
const rdata = JSON.parse(JSON.stringify(res.data))
|
||||
const defaultData = JSON.parse(JSON.stringify(res.data))
|
||||
const sidebarRoutes = filterAsyncRouter(sdata)
|
||||
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
||||
const defaultRoutes = filterAsyncRouter(defaultData)
|
||||
commit('SET_ROUTES', rewriteRoutes)
|
||||
commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
|
||||
commit('SET_DEFAULT_ROUTES', sidebarRoutes)
|
||||
commit('SET_TOPBAR_ROUTES', defaultRoutes)
|
||||
resolve(rewriteRoutes)
|
||||
const usePermissionStore = defineStore(
|
||||
'permission',
|
||||
{
|
||||
state: () => ({
|
||||
routes: [],
|
||||
addRoutes: [],
|
||||
defaultRoutes: [],
|
||||
topbarRouters: [],
|
||||
sidebarRouters: []
|
||||
}),
|
||||
actions: {
|
||||
setRoutes(routes) {
|
||||
this.addRoutes = routes
|
||||
this.routes = constantRoutes.concat(routes)
|
||||
},
|
||||
setDefaultRoutes(routes) {
|
||||
this.defaultRoutes = constantRoutes.concat(routes)
|
||||
},
|
||||
setTopbarRoutes(routes) {
|
||||
this.topbarRouters = routes
|
||||
},
|
||||
setSidebarRouters(routes) {
|
||||
this.sidebarRouters = routes
|
||||
},
|
||||
generateRoutes(roles) {
|
||||
return new Promise(resolve => {
|
||||
// 向后端请求路由数据
|
||||
getRouters().then(res => {
|
||||
const sdata = JSON.parse(JSON.stringify(res.data))
|
||||
const rdata = JSON.parse(JSON.stringify(res.data))
|
||||
const defaultData = JSON.parse(JSON.stringify(res.data))
|
||||
const sidebarRoutes = filterAsyncRouter(sdata)
|
||||
const rewriteRoutes = filterAsyncRouter(rdata, false, true)
|
||||
const defaultRoutes = filterAsyncRouter(defaultData)
|
||||
const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
|
||||
asyncRoutes.forEach(route => { router.addRoute(route) })
|
||||
this.setRoutes(rewriteRoutes)
|
||||
this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
|
||||
this.setDefaultRoutes(sidebarRoutes)
|
||||
this.setTopbarRoutes(defaultRoutes)
|
||||
resolve(rewriteRoutes)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 遍历后台传来的路由字符串,转换为组件对象
|
||||
function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
|
||||
@@ -105,6 +107,23 @@ function filterChildren(childrenMap, lastRouter = false) {
|
||||
return children
|
||||
}
|
||||
|
||||
// 动态路由遍历,验证是否具备权限
|
||||
export function filterDynamicRoutes(routes) {
|
||||
const res = []
|
||||
routes.forEach(route => {
|
||||
if (route.permissions) {
|
||||
if (auth.hasPermiOr(route.permissions)) {
|
||||
res.push(route)
|
||||
}
|
||||
} else if (route.roles) {
|
||||
if (auth.hasRoleOr(route.roles)) {
|
||||
res.push(route)
|
||||
}
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
export const loadView = (view) => {
|
||||
let res;
|
||||
for (const path in modules) {
|
||||
@@ -116,4 +135,4 @@ export const loadView = (view) => {
|
||||
return res;
|
||||
}
|
||||
|
||||
export default permission
|
||||
export default usePermissionStore
|
||||
|
||||
@@ -4,41 +4,35 @@ import { useDynamicTitle } from '@/utils/dynamicTitle'
|
||||
const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
|
||||
|
||||
const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
|
||||
const state = {
|
||||
title: '',
|
||||
theme: storageSetting.theme || '#409EFF',
|
||||
sideTheme: storageSetting.sideTheme || sideTheme,
|
||||
showSettings: showSettings,
|
||||
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
|
||||
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
|
||||
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
|
||||
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
|
||||
dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
|
||||
}
|
||||
const mutations = {
|
||||
CHANGE_SETTING: (state, { key, value }) => {
|
||||
if (state.hasOwnProperty(key)) {
|
||||
state[key] = value
|
||||
|
||||
const useSettingsStore = defineStore(
|
||||
'settings',
|
||||
{
|
||||
state: () => ({
|
||||
title: '',
|
||||
theme: storageSetting.theme || '#409EFF',
|
||||
sideTheme: storageSetting.sideTheme || sideTheme,
|
||||
showSettings: showSettings,
|
||||
topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
|
||||
tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
|
||||
fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
|
||||
sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
|
||||
dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
|
||||
}),
|
||||
actions: {
|
||||
// 修改布局设置
|
||||
changeSetting(data) {
|
||||
const { key, value } = data
|
||||
if (this.hasOwnProperty(key)) {
|
||||
this[key] = value
|
||||
}
|
||||
},
|
||||
// 设置网页标题
|
||||
setTitle(title) {
|
||||
this.title = title
|
||||
useDynamicTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
// 修改布局设置
|
||||
changeSetting({ commit }, data) {
|
||||
commit('CHANGE_SETTING', data)
|
||||
},
|
||||
// 设置网页标题
|
||||
setTitle({ commit }, title) {
|
||||
state.title = title
|
||||
useDynamicTitle();
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
})
|
||||
|
||||
export default useSettingsStore
|
||||
|
||||
@@ -1,207 +1,156 @@
|
||||
const state = {
|
||||
visitedViews: [],
|
||||
cachedViews: []
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
ADD_VISITED_VIEW: (state, view) => {
|
||||
if (state.visitedViews.some(v => v.path === view.path)) return
|
||||
state.visitedViews.push(
|
||||
Object.assign({}, view, {
|
||||
title: view.meta.title || 'no-name'
|
||||
})
|
||||
)
|
||||
},
|
||||
ADD_CACHED_VIEW: (state, view) => {
|
||||
if (state.cachedViews.includes(view.name)) return
|
||||
if (!view.meta.noCache) {
|
||||
state.cachedViews.push(view.name)
|
||||
}
|
||||
},
|
||||
|
||||
DEL_VISITED_VIEW: (state, view) => {
|
||||
for (const [i, v] of state.visitedViews.entries()) {
|
||||
if (v.path === view.path) {
|
||||
state.visitedViews.splice(i, 1)
|
||||
break
|
||||
const useTagsViewStore = defineStore(
|
||||
'tags-view',
|
||||
{
|
||||
state: () => ({
|
||||
visitedViews: [],
|
||||
cachedViews: []
|
||||
}),
|
||||
actions: {
|
||||
addView(view) {
|
||||
this.addVisitedView(view)
|
||||
this.addCachedView(view)
|
||||
},
|
||||
addVisitedView(view) {
|
||||
if (this.visitedViews.some(v => v.path === view.path)) return
|
||||
this.visitedViews.push(
|
||||
Object.assign({}, view, {
|
||||
title: view.meta.title || 'no-name'
|
||||
})
|
||||
)
|
||||
},
|
||||
addCachedView(view) {
|
||||
if (this.cachedViews.includes(view.name)) return
|
||||
if (!view.meta.noCache) {
|
||||
this.cachedViews.push(view.name)
|
||||
}
|
||||
},
|
||||
delView(view) {
|
||||
return new Promise(resolve => {
|
||||
this.delVisitedView(view)
|
||||
this.delCachedView(view)
|
||||
resolve({
|
||||
visitedViews: [...this.visitedViews],
|
||||
cachedViews: [...this.cachedViews]
|
||||
})
|
||||
})
|
||||
},
|
||||
delVisitedView(view) {
|
||||
return new Promise(resolve => {
|
||||
for (const [i, v] of this.visitedViews.entries()) {
|
||||
if (v.path === view.path) {
|
||||
this.visitedViews.splice(i, 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
resolve([...this.visitedViews])
|
||||
})
|
||||
},
|
||||
delCachedView(view) {
|
||||
return new Promise(resolve => {
|
||||
const index = this.cachedViews.indexOf(view.name)
|
||||
index > -1 && this.cachedViews.splice(index, 1)
|
||||
resolve([...this.cachedViews])
|
||||
})
|
||||
},
|
||||
delOthersViews(view) {
|
||||
return new Promise(resolve => {
|
||||
this.delOthersVisitedViews(view)
|
||||
this.delOthersCachedViews(view)
|
||||
resolve({
|
||||
visitedViews: [...this.visitedViews],
|
||||
cachedViews: [...this.cachedViews]
|
||||
})
|
||||
})
|
||||
},
|
||||
delOthersVisitedViews(view) {
|
||||
return new Promise(resolve => {
|
||||
this.visitedViews = this.visitedViews.filter(v => {
|
||||
return v.meta.affix || v.path === view.path
|
||||
})
|
||||
resolve([...this.visitedViews])
|
||||
})
|
||||
},
|
||||
delOthersCachedViews(view) {
|
||||
return new Promise(resolve => {
|
||||
const index = this.cachedViews.indexOf(view.name)
|
||||
if (index > -1) {
|
||||
this.cachedViews = this.cachedViews.slice(index, index + 1)
|
||||
} else {
|
||||
this.cachedViews = []
|
||||
}
|
||||
resolve([...this.cachedViews])
|
||||
})
|
||||
},
|
||||
delAllViews(view) {
|
||||
return new Promise(resolve => {
|
||||
this.delAllVisitedViews(view)
|
||||
this.delAllCachedViews(view)
|
||||
resolve({
|
||||
visitedViews: [...this.visitedViews],
|
||||
cachedViews: [...this.cachedViews]
|
||||
})
|
||||
})
|
||||
},
|
||||
delAllVisitedViews(view) {
|
||||
return new Promise(resolve => {
|
||||
const affixTags = this.visitedViews.filter(tag => tag.meta.affix)
|
||||
this.visitedViews = affixTags
|
||||
resolve([...this.visitedViews])
|
||||
})
|
||||
},
|
||||
delAllCachedViews(view) {
|
||||
return new Promise(resolve => {
|
||||
this.cachedViews = []
|
||||
resolve([...this.cachedViews])
|
||||
})
|
||||
},
|
||||
updateVisitedView(view) {
|
||||
for (let v of this.visitedViews) {
|
||||
if (v.path === view.path) {
|
||||
v = Object.assign(v, view)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
delRightTags(view) {
|
||||
return new Promise(resolve => {
|
||||
const index = this.visitedViews.findIndex(v => v.path === view.path)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
this.visitedViews = this.visitedViews.filter((item, idx) => {
|
||||
if (idx <= index || (item.meta && item.meta.affix)) {
|
||||
return true
|
||||
}
|
||||
const i = this.cachedViews.indexOf(item.name)
|
||||
if (i > -1) {
|
||||
this.cachedViews.splice(i, 1)
|
||||
}
|
||||
return false
|
||||
})
|
||||
resolve([...this.visitedViews])
|
||||
})
|
||||
},
|
||||
delLeftTags(view) {
|
||||
return new Promise(resolve => {
|
||||
const index = this.visitedViews.findIndex(v => v.path === view.path)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
this.visitedViews = this.visitedViews.filter((item, idx) => {
|
||||
if (idx >= index || (item.meta && item.meta.affix)) {
|
||||
return true
|
||||
}
|
||||
const i = this.cachedViews.indexOf(item.name)
|
||||
if (i > -1) {
|
||||
this.cachedViews.splice(i, 1)
|
||||
}
|
||||
return false
|
||||
})
|
||||
resolve([...this.visitedViews])
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
DEL_CACHED_VIEW: (state, view) => {
|
||||
const index = state.cachedViews.indexOf(view.name)
|
||||
index > -1 && state.cachedViews.splice(index, 1)
|
||||
},
|
||||
})
|
||||
|
||||
DEL_OTHERS_VISITED_VIEWS: (state, view) => {
|
||||
state.visitedViews = state.visitedViews.filter(v => {
|
||||
return v.meta.affix || v.path === view.path
|
||||
})
|
||||
},
|
||||
DEL_OTHERS_CACHED_VIEWS: (state, view) => {
|
||||
const index = state.cachedViews.indexOf(view.name)
|
||||
if (index > -1) {
|
||||
state.cachedViews = state.cachedViews.slice(index, index + 1)
|
||||
} else {
|
||||
state.cachedViews = []
|
||||
}
|
||||
},
|
||||
|
||||
DEL_ALL_VISITED_VIEWS: state => {
|
||||
// keep affix tags
|
||||
const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
|
||||
state.visitedViews = affixTags
|
||||
},
|
||||
DEL_ALL_CACHED_VIEWS: state => {
|
||||
state.cachedViews = []
|
||||
},
|
||||
|
||||
UPDATE_VISITED_VIEW: (state, view) => {
|
||||
for (let v of state.visitedViews) {
|
||||
if (v.path === view.path) {
|
||||
v = Object.assign(v, view)
|
||||
break
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
DEL_RIGHT_VIEWS: (state, view) => {
|
||||
const index = state.visitedViews.findIndex(v => v.path === view.path)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
state.visitedViews = state.visitedViews.filter((item, idx) => {
|
||||
if (idx <= index || (item.meta && item.meta.affix)) {
|
||||
return true
|
||||
}
|
||||
const i = state.cachedViews.indexOf(item.name)
|
||||
if (i > -1) {
|
||||
state.cachedViews.splice(i, 1)
|
||||
}
|
||||
return false
|
||||
})
|
||||
},
|
||||
|
||||
DEL_LEFT_VIEWS: (state, view) => {
|
||||
const index = state.visitedViews.findIndex(v => v.path === view.path)
|
||||
if (index === -1) {
|
||||
return
|
||||
}
|
||||
state.visitedViews = state.visitedViews.filter((item, idx) => {
|
||||
if (idx >= index || (item.meta && item.meta.affix)) {
|
||||
return true
|
||||
}
|
||||
const i = state.cachedViews.indexOf(item.name)
|
||||
if (i > -1) {
|
||||
state.cachedViews.splice(i, 1)
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
addView({ dispatch }, view) {
|
||||
dispatch('addVisitedView', view)
|
||||
dispatch('addCachedView', view)
|
||||
},
|
||||
addVisitedView({ commit }, view) {
|
||||
commit('ADD_VISITED_VIEW', view)
|
||||
},
|
||||
addCachedView({ commit }, view) {
|
||||
commit('ADD_CACHED_VIEW', view)
|
||||
},
|
||||
|
||||
delView({ dispatch, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
dispatch('delVisitedView', view)
|
||||
dispatch('delCachedView', view)
|
||||
resolve({
|
||||
visitedViews: [...state.visitedViews],
|
||||
cachedViews: [...state.cachedViews]
|
||||
})
|
||||
})
|
||||
},
|
||||
delVisitedView({ commit, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_VISITED_VIEW', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
delCachedView({ commit, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_CACHED_VIEW', view)
|
||||
resolve([...state.cachedViews])
|
||||
})
|
||||
},
|
||||
|
||||
delOthersViews({ dispatch, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
dispatch('delOthersVisitedViews', view)
|
||||
dispatch('delOthersCachedViews', view)
|
||||
resolve({
|
||||
visitedViews: [...state.visitedViews],
|
||||
cachedViews: [...state.cachedViews]
|
||||
})
|
||||
})
|
||||
},
|
||||
delOthersVisitedViews({ commit, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_OTHERS_VISITED_VIEWS', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
delOthersCachedViews({ commit, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_OTHERS_CACHED_VIEWS', view)
|
||||
resolve([...state.cachedViews])
|
||||
})
|
||||
},
|
||||
|
||||
delAllViews({ dispatch, state }, view) {
|
||||
return new Promise(resolve => {
|
||||
dispatch('delAllVisitedViews', view)
|
||||
dispatch('delAllCachedViews', view)
|
||||
resolve({
|
||||
visitedViews: [...state.visitedViews],
|
||||
cachedViews: [...state.cachedViews]
|
||||
})
|
||||
})
|
||||
},
|
||||
delAllVisitedViews({ commit, state }) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_ALL_VISITED_VIEWS')
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
delAllCachedViews({ commit, state }) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_ALL_CACHED_VIEWS')
|
||||
resolve([...state.cachedViews])
|
||||
})
|
||||
},
|
||||
|
||||
updateVisitedView({ commit }, view) {
|
||||
commit('UPDATE_VISITED_VIEW', view)
|
||||
},
|
||||
|
||||
delRightTags({ commit }, view) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_RIGHT_VIEWS', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
|
||||
delLeftTags({ commit }, view) {
|
||||
return new Promise(resolve => {
|
||||
commit('DEL_LEFT_VIEWS', view)
|
||||
resolve([...state.visitedViews])
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
||||
export default useTagsViewStore
|
||||
|
||||
@@ -2,97 +2,69 @@ import { login, logout, getInfo } from '@/api/login'
|
||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||
import defAva from '@/assets/images/profile.jpg'
|
||||
|
||||
const user = {
|
||||
state: {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
permissions: []
|
||||
},
|
||||
const useUserStore = defineStore(
|
||||
'user',
|
||||
{
|
||||
state: () => ({
|
||||
token: getToken(),
|
||||
name: '',
|
||||
avatar: '',
|
||||
roles: [],
|
||||
permissions: []
|
||||
}),
|
||||
actions: {
|
||||
// 登录
|
||||
login(userInfo) {
|
||||
const username = userInfo.username.trim()
|
||||
const password = userInfo.password
|
||||
const code = userInfo.code
|
||||
const uuid = userInfo.uuid
|
||||
return new Promise((resolve, reject) => {
|
||||
login(username, password, code, uuid).then(res => {
|
||||
setToken(res.token)
|
||||
this.token = res.token
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 获取用户信息
|
||||
getInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(res => {
|
||||
const user = res.user
|
||||
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
|
||||
|
||||
mutations: {
|
||||
SET_TOKEN: (state, token) => {
|
||||
state.token = token
|
||||
},
|
||||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
},
|
||||
SET_ROLES: (state, roles) => {
|
||||
state.roles = roles
|
||||
},
|
||||
SET_PERMISSIONS: (state, permissions) => {
|
||||
state.permissions = permissions
|
||||
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||
this.roles = res.roles
|
||||
this.permissions = res.permissions
|
||||
} else {
|
||||
this.roles = ['ROLE_DEFAULT']
|
||||
}
|
||||
this.name = user.userName
|
||||
this.avatar = avatar;
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// 退出系统
|
||||
logOut() {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout(this.token).then(() => {
|
||||
this.token = ''
|
||||
this.roles = []
|
||||
this.permissions = []
|
||||
removeToken()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
actions: {
|
||||
// 登录
|
||||
Login({ commit }, userInfo) {
|
||||
const username = userInfo.username.trim()
|
||||
const password = userInfo.password
|
||||
const code = userInfo.code
|
||||
const uuid = userInfo.uuid
|
||||
return new Promise((resolve, reject) => {
|
||||
login(username, password, code, uuid).then(res => {
|
||||
setToken(res.token)
|
||||
commit('SET_TOKEN', res.token)
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
GetInfo({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(res => {
|
||||
const user = res.user
|
||||
const avatar = (user.avatar == "" || user.avatar == null) ? defAva : import.meta.env.VITE_APP_BASE_API + user.avatar;
|
||||
|
||||
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
|
||||
commit('SET_ROLES', res.roles)
|
||||
commit('SET_PERMISSIONS', res.permissions)
|
||||
} else {
|
||||
commit('SET_ROLES', ['ROLE_DEFAULT'])
|
||||
}
|
||||
commit('SET_NAME', user.userName)
|
||||
commit('SET_AVATAR', avatar)
|
||||
resolve(res)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 退出系统
|
||||
LogOut({ commit, state }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
logout(state.token).then(() => {
|
||||
commit('SET_TOKEN', '')
|
||||
commit('SET_ROLES', [])
|
||||
commit('SET_PERMISSIONS', [])
|
||||
removeToken()
|
||||
resolve()
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 前端 登出
|
||||
FedLogOut({ commit }) {
|
||||
return new Promise(resolve => {
|
||||
commit('SET_TOKEN', '')
|
||||
removeToken()
|
||||
resolve()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default user
|
||||
export default useUserStore
|
||||
|
||||
@@ -9,7 +9,7 @@ export function useDict(...args) {
|
||||
args.forEach((d, index) => {
|
||||
res.value[d] = [];
|
||||
getDicts(d).then(resp => {
|
||||
res.value[d] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass }))
|
||||
res.value[d] = resp.data.map(p => ({ label: p.dictLabel, value: p.dictValue, elTagType: p.listClass, elTagClass: p.cssClass }))
|
||||
})
|
||||
})
|
||||
return toRefs(res.value);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import store from '@/store'
|
||||
import defaultSettings from '@/settings'
|
||||
import useSettingsStore from '@/store/modules/settings'
|
||||
|
||||
/**
|
||||
* 动态修改标题
|
||||
*/
|
||||
export function useDynamicTitle() {
|
||||
if (store.state.settings.dynamicTitle) {
|
||||
document.title = store.state.settings.title + ' - ' + defaultSettings.title;
|
||||
const settingsStore = useSettingsStore();
|
||||
if (settingsStore.dynamicTitle) {
|
||||
document.title = settingsStore.title + ' - ' + defaultSettings.title;
|
||||
} else {
|
||||
document.title = defaultSettings.title;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import store from '@/store'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
/**
|
||||
* 字符权限校验
|
||||
@@ -7,7 +7,7 @@ import store from '@/store'
|
||||
*/
|
||||
export function checkPermi(value) {
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissions = store.getters && store.getters.permissions
|
||||
const permissions = useUserStore().permissions
|
||||
const permissionDatas = value
|
||||
const all_permission = "*:*:*";
|
||||
|
||||
@@ -32,7 +32,7 @@ export function checkPermi(value) {
|
||||
*/
|
||||
export function checkRole(value) {
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const roles = store.getters && store.getters.roles
|
||||
const roles = useUserStore().roles
|
||||
const permissionRoles = value
|
||||
const super_admin = "admin";
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import axios from 'axios'
|
||||
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import errorCode from '@/utils/errorCode'
|
||||
import { tansParams, blobValidate } from '@/utils/ruoyi'
|
||||
import cache from '@/plugins/cache'
|
||||
import { saveAs } from 'file-saver'
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
let downloadLoadingInstance;
|
||||
// 是否显示重新登录
|
||||
@@ -85,7 +85,7 @@ service.interceptors.response.use(res => {
|
||||
}
|
||||
).then(() => {
|
||||
isRelogin.show = false;
|
||||
store.dispatch('LogOut').then(() => {
|
||||
useUserStore().logOut().then(() => {
|
||||
location.href = '/index';
|
||||
})
|
||||
}).catch(() => {
|
||||
|
||||
@@ -68,7 +68,7 @@ export function addDateRange(params, dateRange, propName) {
|
||||
return search;
|
||||
}
|
||||
|
||||
// 回显数据字典
|
||||
// 回显数据字典
|
||||
export function selectDictLabel(datas, value) {
|
||||
if (value === undefined) {
|
||||
return "";
|
||||
@@ -207,10 +207,10 @@ export function tansParams(params) {
|
||||
for (const propName of Object.keys(params)) {
|
||||
const value = params[propName];
|
||||
var part = encodeURIComponent(propName) + "=";
|
||||
if (value !== null && typeof (value) !== "undefined") {
|
||||
if (value !== null && value !== "" && typeof (value) !== "undefined") {
|
||||
if (typeof value === 'object') {
|
||||
for (const key of Object.keys(value)) {
|
||||
if (value[key] !== null && typeof (value[key]) !== 'undefined') {
|
||||
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
|
||||
let params = propName + '[' + key + ']';
|
||||
var subPart = encodeURIComponent(params) + "=";
|
||||
result += subPart + encodeURIComponent(value[key]) + "&";
|
||||
|
||||
@@ -118,11 +118,11 @@
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
<i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
|
||||
<s>满887144332</s> <s>满180251782</s> <s>满104180207</s> <s>满186866453</s>
|
||||
<s>满201396349</s> <s>满101456076</s> <s>满101539465</s> <s>满264312783</s>
|
||||
<a href="https://jq.qq.com/?_wv=1027&k=SWCtLnMz" target="_blank">
|
||||
167385320</a
|
||||
<i class="el-icon-user-solid"></i> QQ群:<s>满937441</s> <s>满887144332</s>
|
||||
<s>满180251782</s> <s>满104180207</s> <s>满186866453</s> <s>满201396349</s>
|
||||
<s>满101456076</s> <s>满101539465</s> <s>满264312783</s> <s>满167385320</s>
|
||||
<a href="https://jq.qq.com/?_wv=1027&k=DuWxuULe" target="_blank">
|
||||
139821253</a
|
||||
>
|
||||
</p>
|
||||
<p>
|
||||
@@ -149,6 +149,44 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-collapse accordion>
|
||||
<el-collapse-item title="v3.8.3 - 2022-06-27">
|
||||
<ol>
|
||||
<li>新增缓存列表菜单功能</li>
|
||||
<li>代码生成树表新增(展开/折叠)</li>
|
||||
<li>Excel注解支持color字体颜色</li>
|
||||
<li>新增Anonymous匿名访问不鉴权注解</li>
|
||||
<li>用户头像上传限制只能为图片格式</li>
|
||||
<li>接口使用泛型使其看到响应属性字段</li>
|
||||
<li>检查定时任务bean所在包名是否为白名单配置</li>
|
||||
<li>添加页签openPage支持传递参数</li>
|
||||
<li>用户缓存信息添加部门ancestors祖级列表</li>
|
||||
<li>升级element-ui到最新版本2.15.8</li>
|
||||
<li>升级oshi到最新版本6.1.6</li>
|
||||
<li>升级druid到最新版本1.2.11</li>
|
||||
<li>升级fastjson到最新版2.0.8</li>
|
||||
<li>升级spring-boot到最新版本2.5.14</li>
|
||||
<li>降级jsencrypt版本兼容IE浏览器</li>
|
||||
<li>删除多余的salt字段</li>
|
||||
<li>新增获取不带后缀文件名称方法</li>
|
||||
<li>新增获取配置文件中的属性值方法</li>
|
||||
<li>新增内容编码/解码方便插件集成使用</li>
|
||||
<li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li>
|
||||
<li>优化设置分页参数默认值</li>
|
||||
<li>优化对空字符串参数处理的过滤</li>
|
||||
<li>优化显示顺序orderNum类型为整型</li>
|
||||
<li>优化表单构建按钮不显示正则校验</li>
|
||||
<li>优化字典数据回显样式下拉框显示值</li>
|
||||
<li>优化R响应成功状态码与全局保持一致</li>
|
||||
<li>优化druid开启wall过滤器出现的异常问题</li>
|
||||
<li>优化用户管理左侧树型组件增加选中高亮保持</li>
|
||||
<li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
|
||||
<li>优化默认不启用压缩文件缓存防止node_modules过大</li>
|
||||
<li>修复字典数据显示不全问题</li>
|
||||
<li>修复操作日志查询类型条件为0时会查到所有数据</li>
|
||||
<li>修复Excel注解prompt/combo同时使用不生效问题</li>
|
||||
<li>其他细节优化</li>
|
||||
</ol>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="v3.8.2 - 2022-04-01">
|
||||
<ol>
|
||||
<li>前端支持设置是否需要防止数据重复提交</li>
|
||||
@@ -796,7 +834,7 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Index">
|
||||
const version = ref('3.8.2')
|
||||
const version = ref('3.8.3')
|
||||
|
||||
function goTarget(url) {
|
||||
window.open(url, '__blank')
|
||||
|
||||
@@ -68,8 +68,9 @@
|
||||
import { getCodeImg } from "@/api/login";
|
||||
import Cookies from "js-cookie";
|
||||
import { encrypt, decrypt } from "@/utils/jsencrypt";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
const store = useStore();
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter();
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
@@ -99,7 +100,7 @@ function handleLogin() {
|
||||
proxy.$refs.loginRef.validate(valid => {
|
||||
if (valid) {
|
||||
loading.value = true;
|
||||
// 勾选了需要记住密码设置在cookie中设置记住用户明和名命
|
||||
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
|
||||
if (loginForm.value.rememberMe) {
|
||||
Cookies.set("username", loginForm.value.username, { expires: 30 });
|
||||
Cookies.set("password", encrypt(loginForm.value.password), { expires: 30 });
|
||||
@@ -111,7 +112,7 @@ function handleLogin() {
|
||||
Cookies.remove("rememberMe");
|
||||
}
|
||||
// 调用action的登录方法
|
||||
store.dispatch("Login", loginForm.value).then(() => {
|
||||
userStore.login(loginForm.value).then(() => {
|
||||
router.push({ path: redirect.value || "/" });
|
||||
}).catch(() => {
|
||||
loading.value = false;
|
||||
@@ -211,4 +212,4 @@ getCookie();
|
||||
height: 40px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
6
src/views/monitor/cache/index.vue
vendored
6
src/views/monitor/cache/index.vue
vendored
@@ -66,7 +66,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup name="Cache">
|
||||
import { getCache } from '@/api/monitor/cache';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
@@ -98,7 +98,7 @@ function getList() {
|
||||
animationEasing: "cubicInOut",
|
||||
animationDuration: 1000
|
||||
}
|
||||
],
|
||||
]
|
||||
});
|
||||
|
||||
const usedmemoryInstance = echarts.init(usedmemory.value, "macarons");
|
||||
@@ -122,7 +122,7 @@ function getList() {
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
241
src/views/monitor/cache/list.vue
vendored
Normal file
241
src/views/monitor/cache/list.vue
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="8">
|
||||
<el-card style="height: calc(100vh - 125px)">
|
||||
<template #header>
|
||||
<span>缓存列表</span>
|
||||
<el-button
|
||||
style="float: right; padding: 3px 0"
|
||||
type="text"
|
||||
icon="Refresh"
|
||||
@click="refreshCacheNames()"
|
||||
></el-button>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="cacheNames"
|
||||
:height="tableHeight"
|
||||
highlight-current-row
|
||||
@row-click="getCacheKeys"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
width="60"
|
||||
type="index"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="缓存名称"
|
||||
align="center"
|
||||
prop="cacheName"
|
||||
:show-overflow-tooltip="true"
|
||||
:formatter="nameFormatter"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column
|
||||
label="备注"
|
||||
align="center"
|
||||
prop="remark"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="60"
|
||||
align="center"
|
||||
class-name="small-padding fixed-width"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="Delete"
|
||||
@click="handleClearCacheName(scope.row)"
|
||||
></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card style="height: calc(100vh - 125px)">
|
||||
<template #header>
|
||||
<span>键名列表</span>
|
||||
<el-button
|
||||
style="float: right; padding: 3px 0"
|
||||
type="text"
|
||||
icon="Refresh"
|
||||
@click="refreshCacheKeys()"
|
||||
></el-button>
|
||||
</template>
|
||||
<el-table
|
||||
v-loading="subLoading"
|
||||
:data="cacheKeys"
|
||||
:height="tableHeight"
|
||||
highlight-current-row
|
||||
@row-click="handleCacheValue"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
width="60"
|
||||
type="index"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
label="缓存键名"
|
||||
align="center"
|
||||
:show-overflow-tooltip="true"
|
||||
:formatter="keyFormatter"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="60"
|
||||
align="center"
|
||||
class-name="small-padding fixed-width"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="Delete"
|
||||
@click="handleClearCacheKey(scope.row)"
|
||||
></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-card :bordered="false" style="height: calc(100vh - 125px)">
|
||||
<template #header>
|
||||
<span>缓存内容</span>
|
||||
<el-button
|
||||
style="float: right; padding: 3px 0"
|
||||
type="text"
|
||||
icon="Refresh"
|
||||
@click="handleClearCacheAll()"
|
||||
>清理全部</el-button
|
||||
>
|
||||
</template>
|
||||
<el-form :model="cacheForm">
|
||||
<el-row :gutter="32">
|
||||
<el-col :offset="1" :span="22">
|
||||
<el-form-item label="缓存名称:" prop="cacheName">
|
||||
<el-input v-model="cacheForm.cacheName" :readOnly="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :offset="1" :span="22">
|
||||
<el-form-item label="缓存键名:" prop="cacheKey">
|
||||
<el-input v-model="cacheForm.cacheKey" :readOnly="true" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :offset="1" :span="22">
|
||||
<el-form-item label="缓存内容:" prop="cacheValue">
|
||||
<el-input
|
||||
v-model="cacheForm.cacheValue"
|
||||
type="textarea"
|
||||
:rows="8"
|
||||
:readOnly="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="CacheList">
|
||||
import { listCacheName, listCacheKey, getCacheValue, clearCacheName, clearCacheKey, clearCacheAll } from "@/api/monitor/cache";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const cacheNames = ref([]);
|
||||
const cacheKeys = ref([]);
|
||||
const cacheForm = ref({});
|
||||
const loading = ref(true);
|
||||
const subLoading = ref(false);
|
||||
const nowCacheName = ref("");
|
||||
const tableHeight = ref(window.innerHeight - 200);
|
||||
|
||||
/** 查询缓存名称列表 */
|
||||
function getCacheNames() {
|
||||
loading.value = true;
|
||||
listCacheName().then(response => {
|
||||
cacheNames.value = response.data;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/** 刷新缓存名称列表 */
|
||||
function refreshCacheNames() {
|
||||
getCacheNames();
|
||||
proxy.$modal.msgSuccess("刷新缓存列表成功");
|
||||
}
|
||||
|
||||
/** 清理指定名称缓存 */
|
||||
function handleClearCacheName(row) {
|
||||
clearCacheName(row.cacheName).then(response => {
|
||||
proxy.$modal.msgSuccess("清理缓存名称[" + nowCacheName.value + "]成功");
|
||||
getCacheKeys();
|
||||
});
|
||||
}
|
||||
|
||||
/** 查询缓存键名列表 */
|
||||
function getCacheKeys(row) {
|
||||
const cacheName = row !== undefined ? row.cacheName : nowCacheName.value;
|
||||
if (cacheName === "") {
|
||||
return;
|
||||
}
|
||||
subLoading.value = true;
|
||||
listCacheKey(cacheName).then(response => {
|
||||
cacheKeys.value = response.data;
|
||||
subLoading.value = false;
|
||||
nowCacheName.value = cacheName;
|
||||
});
|
||||
}
|
||||
|
||||
/** 刷新缓存键名列表 */
|
||||
function refreshCacheKeys() {
|
||||
getCacheKeys();
|
||||
proxy.$modal.msgSuccess("刷新键名列表成功");
|
||||
}
|
||||
|
||||
/** 清理指定键名缓存 */
|
||||
function handleClearCacheKey(cacheKey) {
|
||||
clearCacheKey(cacheKey).then(response => {
|
||||
proxy.$modal.msgSuccess("清理缓存键名[" + cacheKey + "]成功");
|
||||
getCacheKeys();
|
||||
});
|
||||
}
|
||||
|
||||
/** 列表前缀去除 */
|
||||
function nameFormatter(row) {
|
||||
return row.cacheName.replace(":", "");
|
||||
}
|
||||
|
||||
/** 键名前缀去除 */
|
||||
function keyFormatter(cacheKey) {
|
||||
return cacheKey.replace(nowCacheName.value, "");
|
||||
}
|
||||
|
||||
/** 查询缓存内容详细 */
|
||||
function handleCacheValue(cacheKey) {
|
||||
getCacheValue(nowCacheName.value, cacheKey).then(response => {
|
||||
cacheForm.value = response.data;
|
||||
});
|
||||
}
|
||||
|
||||
/** 清理全部缓存 */
|
||||
function handleClearCacheAll() {
|
||||
clearCacheAll().then(response => {
|
||||
proxy.$modal.msgSuccess("清理全部缓存成功");
|
||||
});
|
||||
}
|
||||
|
||||
getCacheNames();
|
||||
</script>
|
||||
@@ -195,7 +195,7 @@
|
||||
<br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
|
||||
</div>
|
||||
</template>
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<el-card>
|
||||
<template #header><span>Java虚拟机信息</span></template>
|
||||
<div class="el-table el-table--enable-row-hover el-table--medium">
|
||||
<table cellspacing="0" style="width: 100%;">
|
||||
<table cellspacing="0" style="width: 100%;table-layout:fixed;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="el-table__cell is-leaf"><div class="cell">Java名称</div></td>
|
||||
|
||||
@@ -97,11 +97,13 @@
|
||||
<el-row>
|
||||
<el-col :span="24" v-if="form.parentId !== 0">
|
||||
<el-form-item label="上级部门" prop="parentId">
|
||||
<tree-select
|
||||
v-model:value="form.parentId"
|
||||
:options="deptOptions"
|
||||
:objMap="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
||||
<el-tree-select
|
||||
v-model="form.parentId"
|
||||
:data="deptOptions"
|
||||
:props="{ value: 'deptId', label: 'deptName', children: 'children' }"
|
||||
value-key="deptId"
|
||||
placeholder="选择上级部门"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -222,9 +224,9 @@ function resetQuery() {
|
||||
handleQuery();
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
async function handleAdd(row) {
|
||||
function handleAdd(row) {
|
||||
reset();
|
||||
await listDept().then(response => {
|
||||
listDept().then(response => {
|
||||
deptOptions.value = proxy.handleTree(response.data, "deptId");
|
||||
});
|
||||
if (row != undefined) {
|
||||
@@ -242,9 +244,9 @@ function toggleExpandAll() {
|
||||
});
|
||||
}
|
||||
/** 修改按钮操作 */
|
||||
async function handleUpdate(row) {
|
||||
function handleUpdate(row) {
|
||||
reset();
|
||||
await listDeptExcludeChild(row.deptId).then(response => {
|
||||
listDeptExcludeChild(row.deptId).then(response => {
|
||||
deptOptions.value = proxy.handleTree(response.data, "deptId");
|
||||
});
|
||||
getDept(row.deptId).then(response => {
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
<el-option
|
||||
v-for="item in listClassOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:label="item.label + '(' + item.value + ')'"
|
||||
:value="item.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
@@ -185,7 +185,7 @@
|
||||
</template>
|
||||
|
||||
<script setup name="Data">
|
||||
import { listType, getType } from "@/api/system/dict/type";
|
||||
import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
|
||||
import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
@@ -242,8 +242,8 @@ function getTypes(dictId) {
|
||||
|
||||
/** 查询字典类型列表 */
|
||||
function getTypeList() {
|
||||
listType().then(response => {
|
||||
typeOptions.value = response.rows;
|
||||
getDictOptionselect().then(response => {
|
||||
typeOptions.value = response.data;
|
||||
});
|
||||
}
|
||||
/** 查询字典数据列表 */
|
||||
|
||||
@@ -98,16 +98,18 @@
|
||||
</el-table>
|
||||
|
||||
<!-- 添加或修改菜单对话框 -->
|
||||
<el-dialog :title="title" v-model="open" width="680px" :before-close="handleClose" append-to-body>
|
||||
<el-dialog :title="title" v-model="open" width="680px" append-to-body>
|
||||
<el-form ref="menuRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="上级菜单">
|
||||
<tree-select
|
||||
v-model:value="form.parentId"
|
||||
:options="menuOptions"
|
||||
:objMap="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
||||
<el-tree-select
|
||||
v-model="form.parentId"
|
||||
:data="menuOptions"
|
||||
:props="{ value: 'menuId', label: 'menuName', children: 'children' }"
|
||||
value-key="menuId"
|
||||
placeholder="选择上级菜单"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -130,7 +132,7 @@
|
||||
@show="showSelectIcon"
|
||||
>
|
||||
<template #reference>
|
||||
<el-input v-model="form.icon" placeholder="点击选择图标" @click="showSelectIcon" readonly>
|
||||
<el-input v-model="form.icon" placeholder="点击选择图标" @click="showSelectIcon" v-click-outside="hideSelectIcon" readonly>
|
||||
<template #prefix>
|
||||
<svg-icon
|
||||
v-if="form.icon"
|
||||
@@ -161,7 +163,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>是否外链
|
||||
</span>
|
||||
</template>
|
||||
@@ -176,7 +178,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="访问的路由地址,如:`user`,如外网地址需内链访问则以`http(s)://`开头" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
路由地址
|
||||
</span>
|
||||
@@ -189,7 +191,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="访问的组件路径,如:`system/user/index`,默认在`views`目录下" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
组件路径
|
||||
</span>
|
||||
@@ -203,7 +205,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
权限字符
|
||||
</span>
|
||||
@@ -216,7 +218,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content='访问路由的默认传递参数,如:`{"id": 1, "name": "ry"}`' placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
路由参数
|
||||
</span>
|
||||
@@ -228,7 +230,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择是则会被`keep-alive`缓存,需要匹配组件的`name`和地址保持一致" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
是否缓存
|
||||
</span>
|
||||
@@ -244,7 +246,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择隐藏则路由将不会出现在侧边栏,但仍然可以访问" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
显示状态
|
||||
</span>
|
||||
@@ -263,7 +265,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="选择停用则路由将不会出现在侧边栏,也不能被访问" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
菜单状态
|
||||
</span>
|
||||
@@ -293,6 +295,7 @@
|
||||
import { addMenu, delMenu, getMenu, listMenu, updateMenu } from "@/api/system/menu";
|
||||
import SvgIcon from "@/components/SvgIcon";
|
||||
import IconSelect from "@/components/IconSelect";
|
||||
import { ClickOutside as vClickOutside } from 'element-plus'
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { sys_show_hide, sys_normal_disable } = proxy.useDict("sys_show_hide", "sys_normal_disable");
|
||||
@@ -332,9 +335,9 @@ function getList() {
|
||||
});
|
||||
}
|
||||
/** 查询菜单下拉树结构 */
|
||||
async function getTreeselect() {
|
||||
function getTreeselect() {
|
||||
menuOptions.value = [];
|
||||
await listMenu().then(response => {
|
||||
listMenu().then(response => {
|
||||
const menu = { menuId: 0, menuName: "主类目", children: [] };
|
||||
menu.children = proxy.handleTree(response.data, "menuId");
|
||||
menuOptions.value.push(menu);
|
||||
@@ -371,9 +374,8 @@ function selected(name) {
|
||||
form.value.icon = name;
|
||||
showChooseIcon.value = false;
|
||||
}
|
||||
/** 关闭弹窗隐藏图标选择 */
|
||||
function handleClose() {
|
||||
cancel();
|
||||
/** 图标外层点击隐藏下拉列表 */
|
||||
function hideSelectIcon() {
|
||||
showChooseIcon.value = false;
|
||||
}
|
||||
/** 搜索按钮操作 */
|
||||
@@ -386,9 +388,9 @@ function resetQuery() {
|
||||
handleQuery();
|
||||
}
|
||||
/** 新增按钮操作 */
|
||||
async function handleAdd(row) {
|
||||
function handleAdd(row) {
|
||||
reset();
|
||||
await getTreeselect();
|
||||
getTreeselect();
|
||||
if (row != null && row.menuId) {
|
||||
form.value.parentId = row.menuId;
|
||||
} else {
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<template #label>
|
||||
<span>
|
||||
<el-tooltip content="控制器中定义的权限字符,如:@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
权限字符
|
||||
</span>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
:expand-on-click-node="false"
|
||||
:filter-node-method="filterNode"
|
||||
ref="deptTreeRef"
|
||||
highlight-current
|
||||
default-expand-all
|
||||
@node-click="handleNodeClick"
|
||||
/>
|
||||
@@ -207,11 +208,13 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="归属部门" prop="deptId">
|
||||
<tree-select
|
||||
v-model:value="form.deptId"
|
||||
:options="deptOptions"
|
||||
<el-tree-select
|
||||
v-model="form.deptId"
|
||||
:data="deptOptions"
|
||||
:props="{ value: 'id', label: 'label', children: 'children' }"
|
||||
value-key="id"
|
||||
placeholder="请选择归属部门"
|
||||
:objMap="{ value: 'id', label: 'label', children: 'children' }"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -382,7 +385,7 @@ const upload = reactive({
|
||||
// 设置上传的请求头部
|
||||
headers: { Authorization: "Bearer " + getToken() },
|
||||
// 上传的地址
|
||||
url: import.meta.env.VITE_APP_BASE_API + "system/user/importData"
|
||||
url: import.meta.env.VITE_APP_BASE_API + "/system/user/importData"
|
||||
});
|
||||
// 列显隐信息
|
||||
const columns = ref([
|
||||
@@ -539,7 +542,7 @@ const handleFileUploadProgress = (event, file, fileList) => {
|
||||
const handleFileSuccess = (response, file, fileList) => {
|
||||
upload.open = false;
|
||||
upload.isUploading = false;
|
||||
proxy.$refs["uploadRef"].clearFiles();
|
||||
proxy.$refs["uploadRef"].handleRemove(file);
|
||||
proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
|
||||
getList();
|
||||
};
|
||||
@@ -588,7 +591,7 @@ function handleAdd() {
|
||||
roleOptions.value = response.roles;
|
||||
open.value = true;
|
||||
title.value = "添加用户";
|
||||
form.password.value = initPassword.value;
|
||||
form.value.password = initPassword.value;
|
||||
});
|
||||
};
|
||||
/** 修改按钮操作 */
|
||||
|
||||
@@ -54,8 +54,9 @@
|
||||
import "vue-cropper/dist/index.css";
|
||||
import { VueCropper } from "vue-cropper";
|
||||
import { uploadAvatar } from "@/api/system/user";
|
||||
import useUserStore from '@/store/modules/user'
|
||||
|
||||
const store = useStore();
|
||||
const userStore = useUserStore()
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
const open = ref(false);
|
||||
@@ -64,7 +65,7 @@ const title = ref("修改头像");
|
||||
|
||||
//图片裁剪数据
|
||||
const options = reactive({
|
||||
img: store.getters.avatar, // 裁剪图片的地址
|
||||
img: userStore.avatar, // 裁剪图片的地址
|
||||
autoCrop: true, // 是否默认生成截图框
|
||||
autoCropWidth: 200, // 默认生成截图框宽度
|
||||
autoCropHeight: 200, // 默认生成截图框高度
|
||||
@@ -116,7 +117,7 @@ function uploadImg() {
|
||||
uploadAvatar(formData).then(response => {
|
||||
open.value = false;
|
||||
options.img = import.meta.env.VITE_APP_BASE_API + response.imgUrl;
|
||||
store.commit("SET_AVATAR", options.img);
|
||||
userStore.avatar = options.img;
|
||||
proxy.$modal.msgSuccess("修改成功");
|
||||
visible.value = false;
|
||||
});
|
||||
@@ -128,7 +129,7 @@ function realTime(data) {
|
||||
};
|
||||
/** 关闭窗口 */
|
||||
function closeDialog() {
|
||||
options.img = store.getters.avatar;
|
||||
options.img = userStore.avatar;
|
||||
options.visible = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -149,13 +149,13 @@ function submitForm() {
|
||||
Promise.all([basicForm, genForm].map(getFormPromise)).then(res => {
|
||||
const validateResult = res.every(item => !!item);
|
||||
if (validateResult) {
|
||||
const genTable = Object.assign({}, basicForm.model, genForm.model);
|
||||
const genTable = Object.assign({}, info.value);
|
||||
genTable.columns = columns.value;
|
||||
genTable.params = {
|
||||
treeCode: genTable.treeCode,
|
||||
treeName: genTable.treeName,
|
||||
treeParentCode: genTable.treeParentCode,
|
||||
parentMenuId: genTable.parentMenuId
|
||||
treeCode: info.value.treeCode,
|
||||
treeName: info.value.treeName,
|
||||
treeParentCode: info.value.treeParentCode,
|
||||
parentMenuId: info.value.parentMenuId
|
||||
};
|
||||
updateGenTable(genTable).then(res => {
|
||||
proxy.$modal.msgSuccess(res.msg);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<template #label>
|
||||
生成包路径
|
||||
<el-tooltip content="生成在哪个java包下,例如 com.ruoyi.system" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input v-model="info.packageName" />
|
||||
@@ -29,7 +29,7 @@
|
||||
<template #label>
|
||||
生成模块名
|
||||
<el-tooltip content="可理解为子系统名,例如 system" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input v-model="info.moduleName" />
|
||||
@@ -41,7 +41,7 @@
|
||||
<template #label>
|
||||
生成业务名
|
||||
<el-tooltip content="可理解为功能英文名,例如 user" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input v-model="info.businessName" />
|
||||
@@ -53,7 +53,7 @@
|
||||
<template #label>
|
||||
生成功能名
|
||||
<el-tooltip content="用作类描述,例如 用户" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input v-model="info.functionName" />
|
||||
@@ -65,7 +65,7 @@
|
||||
<template #label>
|
||||
上级菜单
|
||||
<el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<tree-select
|
||||
@@ -82,7 +82,7 @@
|
||||
<template #label>
|
||||
生成代码方式
|
||||
<el-tooltip content="默认为zip压缩包下载,也可以自定义生成路径" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
|
||||
@@ -95,7 +95,7 @@
|
||||
<template #label>
|
||||
自定义路径
|
||||
<el-tooltip content="填写磁盘绝对路径,若不填写,则生成到当前Web项目下" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-input v-model="info.genPath">
|
||||
@@ -125,7 +125,7 @@
|
||||
<template #label>
|
||||
树编码字段
|
||||
<el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-select v-model="info.treeCode" placeholder="请选择">
|
||||
@@ -143,7 +143,7 @@
|
||||
<template #label>
|
||||
树父编码字段
|
||||
<el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-select v-model="info.treeParentCode" placeholder="请选择">
|
||||
@@ -161,7 +161,7 @@
|
||||
<template #label>
|
||||
树名称字段
|
||||
<el-tooltip content="树节点的显示名称字段名, 如:dept_name" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-select v-model="info.treeName" placeholder="请选择">
|
||||
@@ -185,7 +185,7 @@
|
||||
<template #label>
|
||||
关联子表的表名
|
||||
<el-tooltip content="关联子表的表名, 如:sys_user" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange">
|
||||
@@ -203,7 +203,7 @@
|
||||
<template #label>
|
||||
子表关联的外键名
|
||||
<el-tooltip content="子表关联的外键名, 如:user_id" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
<el-icon><question-filled /></el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-select v-model="info.subTableFkName" placeholder="请选择">
|
||||
|
||||
@@ -161,8 +161,9 @@
|
||||
v-for="(value, key) in preview.data"
|
||||
:label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
|
||||
:name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
|
||||
:key="key"
|
||||
:key="value"
|
||||
>
|
||||
<el-link :underline="false" icon="DocumentCopy" v-copyText="value" v-copyText:callback="copyTextSuccess" style="float:right"> 复制</el-link>
|
||||
<pre>{{ value }}</pre>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
@@ -274,6 +275,10 @@ function handlePreview(row) {
|
||||
preview.value.activeName = "domain.java";
|
||||
});
|
||||
}
|
||||
/** 复制代码成功 */
|
||||
function copyTextSuccess() {
|
||||
proxy.$modal.msgSuccess("复制成功");
|
||||
}
|
||||
// 多选框选中数据
|
||||
function handleSelectionChange(selection) {
|
||||
ids.value = selection.map(item => item.tableId);
|
||||
|
||||
@@ -5,9 +5,7 @@ export default function createAutoImport() {
|
||||
imports: [
|
||||
'vue',
|
||||
'vue-router',
|
||||
{
|
||||
'vuex': ['useStore']
|
||||
}
|
||||
'pinia'
|
||||
],
|
||||
dts: false
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import svgIcon from 'vite-plugin-svg-icons'
|
||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||
import path from 'path'
|
||||
|
||||
export default function createSvgIcon(isBuild) {
|
||||
return svgIcon({
|
||||
return createSvgIconsPlugin({
|
||||
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons/svg')],
|
||||
symbolId: 'icon-[dir]-[name]',
|
||||
svgoOptions: isBuild
|
||||
|
||||
Reference in New Issue
Block a user