合并
This commit is contained in:
commit
a6d47a8ad4
@ -18,7 +18,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.1.0",
|
"@element-plus/icons-vue": "2.1.0",
|
||||||
"@vueup/vue-quill": "1.1.0",
|
"@vueup/vue-quill": "1.2.0",
|
||||||
"@vueuse/core": "9.5.0",
|
"@vueuse/core": "9.5.0",
|
||||||
"animate.css": "4.1.1",
|
"animate.css": "4.1.1",
|
||||||
"await-to-js": "^3.0.0",
|
"await-to-js": "^3.0.0",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export interface OperLogQuery extends PageQuery {
|
export interface OperLogQuery extends PageQuery {
|
||||||
|
operIp: string;
|
||||||
title: string;
|
title: string;
|
||||||
operName: string;
|
operName: string;
|
||||||
businessType: string;
|
businessType: string;
|
||||||
|
@ -20,7 +20,7 @@ export function getConfig(configId: string | number): AxiosPromise<ConfigVO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 根据参数键名查询参数值
|
// 根据参数键名查询参数值
|
||||||
export function getConfigKey(configKey: string): AxiosPromise<ConfigVO> {
|
export function getConfigKey(configKey: string): AxiosPromise<String> {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/config/configKey/' + configKey,
|
url: '/system/config/configKey/' + configKey,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
|
@ -136,7 +136,7 @@ export const updateUserPwd = (oldPassword: string, newPassword: string) => {
|
|||||||
headers: {
|
headers: {
|
||||||
isEncrypt: true
|
isEncrypt: true
|
||||||
},
|
},
|
||||||
params: data
|
data: data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,23 +227,4 @@
|
|||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the scroll bar appears when the sub-menu is too long
|
|
||||||
> .el-menu--popup {
|
|
||||||
max-height: 100vh;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track-piece {
|
|
||||||
background: #d3dce6;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background: #99a9bf;
|
|
||||||
border-radius: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,13 +9,13 @@
|
|||||||
name="file"
|
name="file"
|
||||||
:show-file-list="false"
|
:show-file-list="false"
|
||||||
:headers="upload.headers"
|
:headers="upload.headers"
|
||||||
style="display: none"
|
ref="uploadRef"
|
||||||
v-if="type === 'url'"
|
v-if="type === 'url'"
|
||||||
>
|
>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<div class="editor">
|
<div class="editor">
|
||||||
<quill-editor
|
<quill-editor
|
||||||
ref="myQuillEditor"
|
ref="quillEditorRef"
|
||||||
v-model:content="content"
|
v-model:content="content"
|
||||||
contentType="html"
|
contentType="html"
|
||||||
@textChange="(e: any) => $emit('update:modelValue', content)"
|
@textChange="(e: any) => $emit('update:modelValue', content)"
|
||||||
@ -53,7 +53,7 @@ const upload = reactive<UploadOption>({
|
|||||||
headers: globalHeaders(),
|
headers: globalHeaders(),
|
||||||
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
|
url: import.meta.env.VITE_APP_BASE_API + '/resource/oss/upload'
|
||||||
})
|
})
|
||||||
const myQuillEditor = ref();
|
const quillEditorRef = ref();
|
||||||
|
|
||||||
const options = ref({
|
const options = ref({
|
||||||
theme: "snow",
|
theme: "snow",
|
||||||
@ -86,7 +86,7 @@ const options = ref({
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
placeholder: '请输入内容',
|
placeholder: "请输入内容",
|
||||||
readOnly: props.readOnly,
|
readOnly: props.readOnly,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,10 +110,10 @@ watch(() => props.modelValue, (v) => {
|
|||||||
|
|
||||||
// 图片上传成功返回图片地址
|
// 图片上传成功返回图片地址
|
||||||
const handleUploadSuccess = (res: any) => {
|
const handleUploadSuccess = (res: any) => {
|
||||||
// 获取富文本实例
|
|
||||||
let quill = toRaw(myQuillEditor.value).getQuill();
|
|
||||||
// 如果上传成功
|
// 如果上传成功
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
|
// 获取富文本实例
|
||||||
|
let quill = toRaw(quillEditorRef.value).getQuill();
|
||||||
// 获取光标位置
|
// 获取光标位置
|
||||||
let length = quill.selection.savedRange.index;
|
let length = quill.selection.savedRange.index;
|
||||||
// 插入图片,res为服务器返回的图片链接地址
|
// 插入图片,res为服务器返回的图片链接地址
|
||||||
@ -129,6 +129,13 @@ const handleUploadSuccess = (res: any) => {
|
|||||||
|
|
||||||
// 图片上传前拦截
|
// 图片上传前拦截
|
||||||
const handleBeforeUpload = (file: any) => {
|
const handleBeforeUpload = (file: any) => {
|
||||||
|
const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
|
||||||
|
const isJPG = type.includes(file.type);
|
||||||
|
//检验文件格式
|
||||||
|
if (!isJPG) {
|
||||||
|
proxy?.$modal.msgError(`图片格式错误!`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 校检文件大小
|
// 校检文件大小
|
||||||
if (props.fileSize) {
|
if (props.fileSize) {
|
||||||
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
const isLt = file.size / 1024 / 1024 < props.fileSize;
|
||||||
@ -149,95 +156,80 @@ const handleUploadError = (err: any) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.editor-img-uploader {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
.editor,
|
.editor,
|
||||||
.ql-toolbar {
|
.ql-toolbar {
|
||||||
white-space: pre-wrap !important;
|
white-space: pre-wrap !important;
|
||||||
line-height: normal !important;
|
line-height: normal !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.quill-img {
|
.quill-img {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
.ql-snow .ql-tooltip[data-mode="link"]::before {
|
||||||
content: "请输入链接地址:";
|
content: "请输入链接地址:";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
content: "保存";
|
content: "保存";
|
||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-tooltip[data-mode="video"]::before {
|
.ql-snow .ql-tooltip[data-mode="video"]::before {
|
||||||
content: "请输入视频地址:";
|
content: "请输入视频地址:";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||||
content: "14px";
|
content: "14px";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
|
||||||
content: "10px";
|
content: "10px";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
|
||||||
content: "18px";
|
content: "18px";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
|
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
|
||||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
|
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
|
||||||
content: "32px";
|
content: "32px";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||||
content: "文本";
|
content: "文本";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||||
content: "标题1";
|
content: "标题1";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||||
content: "标题2";
|
content: "标题2";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||||
content: "标题3";
|
content: "标题3";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||||
content: "标题4";
|
content: "标题4";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||||
content: "标题5";
|
content: "标题5";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||||
content: "标题6";
|
content: "标题6";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||||
content: "标准字体";
|
content: "标准字体";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
|
||||||
content: "衬线字体";
|
content: "衬线字体";
|
||||||
}
|
}
|
||||||
|
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
|
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
|
||||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
|
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
|
||||||
content: "等宽字体";
|
content: "等宽字体";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :class="{ 'show': show }" class="header-search">
|
<div :class="{ 'show': show }" class="header-search">
|
||||||
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
|
<svg-icon class-name="search-icon" icon-class="search" @click.stop="click"/>
|
||||||
<el-select
|
<el-select
|
||||||
ref="headerSearchSelectRef"
|
ref="headerSearchSelectRef"
|
||||||
v-model="search"
|
v-model="search"
|
||||||
@ -12,21 +12,22 @@
|
|||||||
class="header-search-select"
|
class="header-search-select"
|
||||||
@change="change"
|
@change="change"
|
||||||
>
|
>
|
||||||
<el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
|
<el-option v-for="option in options" :key="option.item.path" :value="option.item"
|
||||||
|
:label="option.item.title.join(' > ')"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="HeaderSearch">
|
<script setup lang="ts" name="HeaderSearch">
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
import { getNormalPath } from '@/utils/ruoyi';
|
import {getNormalPath} from '@/utils/ruoyi';
|
||||||
import { isHttp } from '@/utils/validate';
|
import {isHttp} from '@/utils/validate';
|
||||||
import usePermissionStore from '@/store/modules/permission';
|
import usePermissionStore from '@/store/modules/permission';
|
||||||
import { RouteOption } from 'vue-router';
|
import {RouteOption} from 'vue-router';
|
||||||
|
|
||||||
type Router = Array<{
|
type Router = Array<{
|
||||||
path: string;
|
path: string;
|
||||||
title: string[];
|
title: string[];
|
||||||
}>
|
}>
|
||||||
|
|
||||||
const search = ref('');
|
const search = ref('');
|
||||||
@ -39,88 +40,99 @@ const router = useRouter();
|
|||||||
const routes = computed(() => usePermissionStore().routes);
|
const routes = computed(() => usePermissionStore().routes);
|
||||||
|
|
||||||
const click = () => {
|
const click = () => {
|
||||||
show.value = !show.value
|
show.value = !show.value
|
||||||
if (show.value) {
|
if (show.value) {
|
||||||
headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
|
headerSearchSelectRef.value && headerSearchSelectRef.value.focus()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const close = () => {
|
const close = () => {
|
||||||
headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
|
headerSearchSelectRef.value && headerSearchSelectRef.value.blur()
|
||||||
options.value = []
|
options.value = []
|
||||||
show.value = false
|
show.value = false
|
||||||
}
|
}
|
||||||
const change = (val: any) => {
|
const change = (val: any) => {
|
||||||
const path = val.path;
|
const path = val.path;
|
||||||
if (isHttp(path)) {
|
const query = val.query;
|
||||||
// http(s):// 路径新窗口打开
|
if (isHttp(path)) {
|
||||||
const pindex = path.indexOf("http");
|
// http(s):// 路径新窗口打开
|
||||||
window.open(path.substr(pindex, path.length), "_blank");
|
const pindex = path.indexOf("http");
|
||||||
|
window.open(path.substr(pindex, path.length), "_blank");
|
||||||
|
} else {
|
||||||
|
if (query) {
|
||||||
|
router.push({ path: path, query: JSON.parse(query) });
|
||||||
} else {
|
} else {
|
||||||
router.push(path)
|
router.push(path)
|
||||||
}
|
}
|
||||||
search.value = ''
|
}
|
||||||
options.value = []
|
search.value = ''
|
||||||
nextTick(() => {
|
options.value = []
|
||||||
show.value = false
|
nextTick(() => {
|
||||||
})
|
show.value = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
const initFuse = (list: Router) => {
|
const initFuse = (list: Router) => {
|
||||||
fuse.value = new Fuse(list, {
|
fuse.value = new Fuse(list, {
|
||||||
shouldSort: true,
|
shouldSort: true,
|
||||||
threshold: 0.4,
|
threshold: 0.4,
|
||||||
location: 0,
|
location: 0,
|
||||||
distance: 100,
|
distance: 100,
|
||||||
minMatchCharLength: 1,
|
minMatchCharLength: 1,
|
||||||
keys: [{
|
keys: [{
|
||||||
name: 'title',
|
name: 'title',
|
||||||
weight: 0.7
|
weight: 0.7
|
||||||
}, {
|
}, {
|
||||||
name: 'path',
|
name: 'path',
|
||||||
weight: 0.3
|
weight: 0.3
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Filter out the routes that can be displayed in the sidebar
|
// Filter out the routes that can be displayed in the sidebar
|
||||||
// And generate the internationalized title
|
// And generate the internationalized title
|
||||||
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = []) => {
|
const generateRoutes = (routes: RouteOption[], basePath = '', prefixTitle: string[] = [], query: any = {}) => {
|
||||||
let res: Router = []
|
let res: Router = []
|
||||||
routes.forEach(r => {
|
routes.forEach(r => {
|
||||||
// skip hidden router
|
// skip hidden router
|
||||||
if (!r.hidden) {
|
if (!r.hidden) {
|
||||||
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
const p = r.path.length > 0 && r.path[0] === '/' ? r.path : '/' + r.path;
|
||||||
const data = {
|
const data = {
|
||||||
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
path: !isHttp(r.path) ? getNormalPath(basePath + p) : r.path,
|
||||||
title: [...prefixTitle]
|
title: [...prefixTitle],
|
||||||
}
|
query: ''
|
||||||
if (r.meta && r.meta.title) {
|
}
|
||||||
data.title = [...data.title, r.meta.title];
|
if (r.meta && r.meta.title) {
|
||||||
if (r.redirect !== 'noRedirect') {
|
data.title = [...data.title, r.meta.title];
|
||||||
// only push the routes with title
|
if (r.redirect !== 'noRedirect') {
|
||||||
// special case: need to exclude parent router without redirect
|
// only push the routes with title
|
||||||
res.push(data);
|
// special case: need to exclude parent router without redirect
|
||||||
}
|
res.push(data);
|
||||||
}
|
|
||||||
// recursive child routes
|
|
||||||
if (r.children) {
|
|
||||||
const tempRoutes = generateRoutes(r.children, data.path, data.title);
|
|
||||||
if (tempRoutes.length >= 1) {
|
|
||||||
res = [...res, ...tempRoutes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
return res;
|
|
||||||
|
if (r.query) {
|
||||||
|
data.query = r.query
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive child routes
|
||||||
|
if (r.children) {
|
||||||
|
const tempRoutes = generateRoutes(r.children, data.path, data.title, data.query);
|
||||||
|
if (tempRoutes.length >= 1) {
|
||||||
|
res = [...res, ...tempRoutes];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
const querySearch = (query: string) => {
|
const querySearch = (query: string) => {
|
||||||
if (query !== '') {
|
if (query !== '') {
|
||||||
options.value = fuse.value.search(query)
|
options.value = fuse.value.search(query)
|
||||||
} else {
|
} else {
|
||||||
options.value = []
|
options.value = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
searchPool.value = generateRoutes(routes.value);
|
searchPool.value = generateRoutes(routes.value);
|
||||||
})
|
})
|
||||||
|
|
||||||
// watchEffect(() => {
|
// watchEffect(() => {
|
||||||
@ -128,54 +140,54 @@ onMounted(() => {
|
|||||||
// })
|
// })
|
||||||
|
|
||||||
watch(show, (value) => {
|
watch(show, (value) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
document.body.addEventListener('click', close)
|
document.body.addEventListener('click', close)
|
||||||
} else {
|
} else {
|
||||||
document.body.removeEventListener('click', close)
|
document.body.removeEventListener('click', close)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(searchPool, (list) => {
|
watch(searchPool, (list) => {
|
||||||
initFuse(list)
|
initFuse(list)
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.header-search {
|
.header-search {
|
||||||
font-size: 0 !important;
|
font-size: 0 !important;
|
||||||
|
|
||||||
.search-icon {
|
.search-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-search-select {
|
||||||
|
font-size: 18px;
|
||||||
|
transition: width 0.2s;
|
||||||
|
width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 0;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
:deep(.el-input__inner) {
|
||||||
|
border-radius: 0;
|
||||||
|
border: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
box-shadow: none !important;
|
||||||
|
border-bottom: 1px solid #d9d9d9;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.show {
|
||||||
.header-search-select {
|
.header-search-select {
|
||||||
font-size: 18px;
|
width: 210px;
|
||||||
transition: width 0.2s;
|
margin-left: 10px;
|
||||||
width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
background: transparent;
|
|
||||||
border-radius: 0;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
:deep(.el-input__inner) {
|
|
||||||
border-radius: 0;
|
|
||||||
border: 0;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 0;
|
|
||||||
box-shadow: none !important;
|
|
||||||
border-bottom: 1px solid #d9d9d9;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.show {
|
|
||||||
.header-search-select {
|
|
||||||
width: 210px;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -7,13 +7,25 @@
|
|||||||
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
<el-tooltip class="item" effect="dark" content="刷新" placement="top">
|
||||||
<el-button circle icon="Refresh" @click="refresh()" />
|
<el-button circle icon="Refresh" @click="refresh()" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip class="item" effect="dark" content="显隐列" placement="top" v-if="columns">
|
<el-tooltip class="item" effect="dark" content="显示/隐藏列" placement="top" v-if="columns">
|
||||||
<el-button circle icon="Menu" @click="showColumn()" />
|
<div>
|
||||||
|
<el-popover placement="bottom" trigger="click">
|
||||||
|
<div class="tree-header">显示/隐藏列</div>
|
||||||
|
<el-tree
|
||||||
|
ref="columnRef"
|
||||||
|
:data="columns"
|
||||||
|
show-checkbox
|
||||||
|
@check="columnChange"
|
||||||
|
node-key="key"
|
||||||
|
:props="{ label: 'label', children: 'children' }"
|
||||||
|
></el-tree>
|
||||||
|
<template #reference>
|
||||||
|
<el-button circle icon="Menu" />
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-dialog :title="title" v-model="open" append-to-body>
|
|
||||||
<el-transfer :titles="['显示', '隐藏']" v-model="value" :data="columns" @change="dataChange"></el-transfer>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -29,15 +41,9 @@ const props = defineProps({
|
|||||||
gutter: propTypes.number.def(10),
|
gutter: propTypes.number.def(10),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const columnRef = ref<ElTreeInstance>();
|
||||||
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
const emits = defineEmits(['update:showSearch', 'queryTable']);
|
||||||
|
|
||||||
// 显隐数据
|
|
||||||
const value = ref<Array<number>>([]);
|
|
||||||
// 弹出层标题
|
|
||||||
const title = ref("显示/隐藏");
|
|
||||||
// 是否显示弹出层
|
|
||||||
const open = ref(false);
|
|
||||||
|
|
||||||
const style = computed(() => {
|
const style = computed(() => {
|
||||||
const ret: any = {};
|
const ret: any = {};
|
||||||
if (props.gutter) {
|
if (props.gutter) {
|
||||||
@ -56,23 +62,19 @@ function refresh() {
|
|||||||
emits("queryTable");
|
emits("queryTable");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 右侧列表元素变化
|
// 更改数据列的显示和隐藏
|
||||||
function dataChange(data: TransferKey[]) {
|
function columnChange(...args: any[]) {
|
||||||
props.columns?.forEach((item) => {
|
props.columns?.forEach((item) => {
|
||||||
item.visible = !data.includes(item.key);
|
item.visible = args[1].checkedKeys.includes(item.key);
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// 打开显隐列dialog
|
|
||||||
const showColumn = () => {
|
|
||||||
open.value = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显隐列初始默认隐藏列
|
// 显隐列初始默认隐藏列
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
props.columns?.forEach((item) => {
|
props.columns?.forEach((item) => {
|
||||||
if (!item.visible) {
|
if (item.visible) {
|
||||||
value.value.push(item.key);
|
columnRef.value?.setChecked(item.key, true, false);
|
||||||
|
// value.value.push(item.key);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -91,4 +93,9 @@ onMounted(() => {
|
|||||||
.my-el-transfer {
|
.my-el-transfer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
.tree-header{
|
||||||
|
width: 100%;
|
||||||
|
line-height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!item.hidden">
|
<div v-if="!item.hidden">
|
||||||
<template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
|
<template v-if="hasOneShowingChild(item, item.children) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
|
||||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
|
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
|
||||||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
|
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{ 'submenu-title-noDropdown': !isNest }">
|
||||||
<svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
|
<svg-icon :icon-class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
|
||||||
@ -18,10 +18,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<sidebar-item
|
<sidebar-item
|
||||||
v-for="child in item.children"
|
v-for="(child) in item.children as RouteOption[]"
|
||||||
:key="child.path"
|
:key="child.path"
|
||||||
:is-nest="true"
|
:is-nest="true"
|
||||||
:item="child as RouteOption"
|
:item="child"
|
||||||
:base-path="resolvePath(child.path)"
|
:base-path="resolvePath(child.path)"
|
||||||
class="nest-menu"
|
class="nest-menu"
|
||||||
/>
|
/>
|
||||||
@ -34,7 +34,6 @@ import { isExternal } from '@/utils/validate'
|
|||||||
import AppLink from './Link.vue'
|
import AppLink from './Link.vue'
|
||||||
import { getNormalPath } from '@/utils/ruoyi'
|
import { getNormalPath } from '@/utils/ruoyi'
|
||||||
import { RouteOption } from "vue-router";
|
import { RouteOption } from "vue-router";
|
||||||
import { PropType } from "vue";
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
// route object
|
// route object
|
||||||
@ -54,7 +53,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const onlyOneChild = ref<any>({});
|
const onlyOneChild = ref<any>({});
|
||||||
|
|
||||||
const hasOneShowingChild = (children:RouteOption[] = [], parent: RouteOption) => {
|
const hasOneShowingChild = (parent: RouteOption, children?:RouteOption[]) => {
|
||||||
if (!children) {
|
if (!children) {
|
||||||
children = [];
|
children = [];
|
||||||
}
|
}
|
||||||
@ -76,9 +75,13 @@ const hasOneShowingChild = (children:RouteOption[] = [], parent: RouteOption) =>
|
|||||||
// Show parent if there are no child router to display
|
// Show parent if there are no child router to display
|
||||||
if (showingChildren.length === 0) {
|
if (showingChildren.length === 0) {
|
||||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
||||||
|
if (parent.name === '2222') {
|
||||||
|
console.log(onlyOneChild.value)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
<el-scrollbar :class="sideTheme" wrap-class="scrollbar-wrapper">
|
||||||
<transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
|
<transition :enter-active-class="proxy?.animate.menuSearchAnimate.enter" mode="out-in">
|
||||||
<el-menu
|
<el-menu
|
||||||
:default-active="activeMenu as string"
|
:default-active="activeMenu"
|
||||||
:collapse="isCollapse"
|
:collapse="isCollapse"
|
||||||
:background-color="bgColor"
|
:background-color="bgColor"
|
||||||
:text-color="textColor"
|
:text-color="textColor"
|
||||||
@ -27,6 +27,7 @@ import variables from '@/assets/styles/variables.module.scss'
|
|||||||
import useAppStore from '@/store/modules/app'
|
import useAppStore from '@/store/modules/app'
|
||||||
import useSettingsStore from '@/store/modules/settings'
|
import useSettingsStore from '@/store/modules/settings'
|
||||||
import usePermissionStore from '@/store/modules/permission'
|
import usePermissionStore from '@/store/modules/permission'
|
||||||
|
import { RouteOption } from "vue-router";
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -34,7 +35,7 @@ const appStore = useAppStore()
|
|||||||
const settingsStore = useSettingsStore()
|
const settingsStore = useSettingsStore()
|
||||||
const permissionStore = usePermissionStore()
|
const permissionStore = usePermissionStore()
|
||||||
|
|
||||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters);
|
const sidebarRouters = computed<RouteOption[]>(() => permissionStore.sidebarRouters);
|
||||||
const showLogo = computed(() => settingsStore.sidebarLogo);
|
const showLogo = computed(() => settingsStore.sidebarLogo);
|
||||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||||
const theme = computed(() => settingsStore.theme);
|
const theme = computed(() => settingsStore.theme);
|
||||||
|
1
src/types/global.d.ts
vendored
1
src/types/global.d.ts
vendored
@ -13,6 +13,7 @@ declare global {
|
|||||||
key: number;
|
key: number;
|
||||||
label: string;
|
label: string;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
|
children?: Array<FieldOption>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
<div class="mb-[10px]">
|
<div class="mb-[10px]">
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
<el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||||
|
<el-form-item label="操作地址" prop="operIp">
|
||||||
|
<el-input v-model="queryParams.operIp" placeholder="请输入操作地址" clearable style="width: 240px;" @keyup.enter="handleQuery"/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="系统模块" prop="title">
|
<el-form-item label="系统模块" prop="title">
|
||||||
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
<el-input v-model="queryParams.title" placeholder="请输入系统模块" clearable style="width: 240px;" @keyup.enter="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -83,7 +86,7 @@
|
|||||||
sortable="custom"
|
sortable="custom"
|
||||||
:sort-orders="['descending', 'ascending']"
|
:sort-orders="['descending', 'ascending']"
|
||||||
/>
|
/>
|
||||||
<el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
|
<el-table-column label="操作地址" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
|
||||||
<el-table-column label="操作状态" align="center" prop="status">
|
<el-table-column label="操作状态" align="center" prop="status">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<dict-tag :options="sys_common_status" :value="scope.row.status" />
|
<dict-tag :options="sys_common_status" :value="scope.row.status" />
|
||||||
@ -215,6 +218,7 @@ const data = reactive<PageData<OperLogForm, OperLogQuery>>({
|
|||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
|
operIp: '',
|
||||||
title: '',
|
title: '',
|
||||||
operName: '',
|
operName: '',
|
||||||
businessType: '',
|
businessType: '',
|
||||||
|
@ -229,7 +229,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" v-if="form.menuType !== 'F'">
|
<el-col :span="12">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
<span>
|
<span>
|
||||||
|
@ -194,7 +194,7 @@ const { queryParams, form, rules } = toRefs(data);
|
|||||||
const getList = async () => {
|
const getList = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
|
const res = await proxy?.getConfigKey("sys.oss.previewListResource");
|
||||||
previewListResource.value = res?.msg === undefined ? true : res.msg === 'true';
|
previewListResource.value = res?.data === undefined ? true : res.data === 'true';
|
||||||
const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime"));
|
const response = await listOss(proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, "CreateTime"));
|
||||||
ossList.value = response.rows;
|
ossList.value = response.rows;
|
||||||
total.value = response.total;
|
total.value = response.total;
|
||||||
|
@ -320,7 +320,7 @@ const total = ref(0);
|
|||||||
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
const dateRange = ref<[DateModelType, DateModelType]>(['', '']);
|
||||||
const deptName = ref('');
|
const deptName = ref('');
|
||||||
const deptOptions = ref<DeptVO[]>([]);
|
const deptOptions = ref<DeptVO[]>([]);
|
||||||
const initPassword = ref('123456');
|
const initPassword = ref<String>('');
|
||||||
const postOptions = ref<PostVO[]>([]);
|
const postOptions = ref<PostVO[]>([]);
|
||||||
const roleOptions = ref<RoleVO[]>([]);
|
const roleOptions = ref<RoleVO[]>([]);
|
||||||
/*** 用户导入参数 */
|
/*** 用户导入参数 */
|
||||||
@ -340,13 +340,13 @@ const upload = reactive<ImportOption>({
|
|||||||
})
|
})
|
||||||
// 列显隐信息
|
// 列显隐信息
|
||||||
const columns = ref<FieldOption[]>([
|
const columns = ref<FieldOption[]>([
|
||||||
{ key: 0, label: `用户编号`, visible: false },
|
{ key: 0, label: `用户编号`, visible: false,children: [] },
|
||||||
{ key: 1, label: `用户名称`, visible: true },
|
{ key: 1, label: `用户名称`, visible: true,children: [] },
|
||||||
{ key: 2, label: `用户昵称`, visible: true },
|
{ key: 2, label: `用户昵称`, visible: true,children: [] },
|
||||||
{ key: 3, label: `部门`, visible: true },
|
{ key: 3, label: `部门`, visible: true,children: [] },
|
||||||
{ key: 4, label: `手机号码`, visible: true },
|
{ key: 4, label: `手机号码`, visible: true,children: [] },
|
||||||
{ key: 5, label: `状态`, visible: true },
|
{ key: 5, label: `状态`, visible: true,children: [] },
|
||||||
{ key: 6, label: `创建时间`, visible: true }
|
{ key: 6, label: `创建时间`, visible: true,children: [] }
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
@ -561,7 +561,7 @@ const handleAdd = async () => {
|
|||||||
await initTreeData();
|
await initTreeData();
|
||||||
postOptions.value = data.posts;
|
postOptions.value = data.posts;
|
||||||
roleOptions.value = data.roles;
|
roleOptions.value = data.roles;
|
||||||
form.value.password = initPassword.value;
|
form.value.password = initPassword.value.toString();
|
||||||
}
|
}
|
||||||
/** 修改按钮操作 */
|
/** 修改按钮操作 */
|
||||||
const handleUpdate = async (row?: UserForm) => {
|
const handleUpdate = async (row?: UserForm) => {
|
||||||
@ -613,6 +613,9 @@ const resetForm = () => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTreeSelect() // 初始化部门数据
|
getTreeSelect() // 初始化部门数据
|
||||||
getList() // 初始化列表数据
|
getList() // 初始化列表数据
|
||||||
|
proxy?.getConfigKey("sys.user.initPassword").then(response => {
|
||||||
|
initPassword.value = response.data;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user