mirror of
https://gitee.com/JavaLionLi/plus-ui.git
synced 2026-03-10 20:00:23 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
656366d610 | ||
|
|
eb8bdd5655 | ||
|
|
1681a32dbc | ||
|
|
705e68759d | ||
|
|
6208a2d0ca | ||
|
|
9cae1bb675 | ||
|
|
6b9802dfe1 |
@@ -81,7 +81,7 @@
|
||||
"vue-tsc": "^2.2.12"
|
||||
},
|
||||
"overrides": {
|
||||
"quill": "2.0.2"
|
||||
"quill": "1.3.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.15.0",
|
||||
|
||||
@@ -43,7 +43,7 @@ export interface ButtonList {
|
||||
}
|
||||
export interface FlowCopyVo {
|
||||
userId: string | number;
|
||||
userName: string;
|
||||
nickName: string;
|
||||
}
|
||||
|
||||
export interface TaskOperationBo {
|
||||
@@ -53,6 +53,8 @@ export interface TaskOperationBo {
|
||||
userIds?: string[];
|
||||
//任务ID(必填)
|
||||
taskId: string | number;
|
||||
//消息类型
|
||||
messageType?: string[];
|
||||
//意见或备注信息(可选)
|
||||
message?: string;
|
||||
}
|
||||
|
||||
@@ -282,3 +282,9 @@ h6 {
|
||||
.top-right-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
/* horizontal el menu */
|
||||
.el-menu--horizontal .el-menu-item .svg-icon + span,
|
||||
.el-menu--horizontal .el-sub-menu__title .svg-icon + span {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,8 @@ const handleTransferTask = async (data) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userId: data[0].userId,
|
||||
taskId: task.value.id,
|
||||
message: ''
|
||||
message: '',
|
||||
messageType: ['1']
|
||||
});
|
||||
await proxy?.$modal.confirm('是否确认提交?');
|
||||
loading.value = true;
|
||||
@@ -139,7 +140,8 @@ const addMultiInstanceUser = async (data) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userIds: data.map((e) => e.userId),
|
||||
taskId: task.value.id,
|
||||
message: ''
|
||||
message: '',
|
||||
messageType: ['1']
|
||||
});
|
||||
await proxy?.$modal.confirm('是否确认提交?');
|
||||
loading.value = true;
|
||||
@@ -163,7 +165,8 @@ const deleteMultiInstanceUser = async (row) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userIds: [row.userId],
|
||||
taskId: task.value.id,
|
||||
message: ''
|
||||
message: '',
|
||||
messageType: ['1']
|
||||
});
|
||||
await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
|
||||
loading.value = false;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<el-form-item label="抄送" v-if="buttonObj.copy">
|
||||
<el-button type="primary" icon="Plus" circle @click="openUserSelectCopy" />
|
||||
<el-tag v-for="user in selectCopyUserList" :key="user.userId" closable style="margin: 2px" @close="handleCopyCloseTag(user)">
|
||||
{{ user.userName }}
|
||||
{{ user.nickName }}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="buttonObj.pop && nestNodeList && nestNodeList.length > 0" label="下一步审批人" prop="assigneeMap">
|
||||
@@ -80,7 +80,13 @@
|
||||
<!-- 加签组件 -->
|
||||
<UserSelect ref="multiInstanceUserRef" :multiple="true" @confirm-call-back="addMultiInstanceUser"></UserSelect>
|
||||
<!-- 弹窗选人 -->
|
||||
<UserSelect ref="porUserRef" :data="form.assigneeMap[nodeCode]" :multiple="true" :userIds="popUserIds" @confirm-call-back="handlePopUser"></UserSelect>
|
||||
<UserSelect
|
||||
ref="porUserRef"
|
||||
:data="form.assigneeMap[nodeCode]"
|
||||
:multiple="true"
|
||||
:userIds="popUserIds"
|
||||
@confirm-call-back="handlePopUser"
|
||||
></UserSelect>
|
||||
|
||||
<!-- 驳回开始 -->
|
||||
<el-dialog v-model="backVisible" draggable title="驳回" width="40%" :close-on-click-modal="false">
|
||||
@@ -265,7 +271,7 @@ const openDialog = async (id?: string) => {
|
||||
selectCopyUserList.value = task.value.copyList;
|
||||
selectCopyUserIds.value = task.value.copyList.map((e) => e.userId).join(',');
|
||||
varNodeList.value = task.value.varList;
|
||||
console.log('varNodeList', varNodeList.value)
|
||||
console.log('varNodeList', varNodeList.value);
|
||||
buttonDisabled.value = false;
|
||||
try {
|
||||
const data = {
|
||||
@@ -310,7 +316,7 @@ const handleCompleteTask = async () => {
|
||||
selectCopyUserList.value.forEach((e) => {
|
||||
const copyUser = {
|
||||
userId: e.userId,
|
||||
userName: e.userName
|
||||
nickName: e.nickName
|
||||
};
|
||||
flowCopyList.push(copyUser);
|
||||
});
|
||||
@@ -397,7 +403,8 @@ const addMultiInstanceUser = async (data) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userIds: data.map((e) => e.userId),
|
||||
taskId: taskId.value,
|
||||
message: form.value.message
|
||||
message: form.value.message,
|
||||
messageType: ['1']
|
||||
});
|
||||
await proxy?.$modal.confirm('是否确认提交?');
|
||||
loading.value = true;
|
||||
@@ -421,7 +428,8 @@ const deleteMultiInstanceUser = async (row) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userIds: [row.userId],
|
||||
taskId: taskId.value,
|
||||
message: form.value.message
|
||||
message: form.value.message,
|
||||
messageType: ['1']
|
||||
});
|
||||
await taskOperation(taskOperationBo, 'reductionSignature').finally(() => {
|
||||
loading.value = false;
|
||||
@@ -441,7 +449,8 @@ const handleTransferTask = async (data) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userId: data[0].userId,
|
||||
taskId: taskId.value,
|
||||
message: form.value.message
|
||||
message: form.value.message,
|
||||
messageType: ['1']
|
||||
});
|
||||
await proxy?.$modal.confirm('是否确认提交?');
|
||||
loading.value = true;
|
||||
@@ -468,7 +477,8 @@ const handleDelegateTask = async (data) => {
|
||||
const taskOperationBo = reactive<TaskOperationBo>({
|
||||
userId: data[0].userId,
|
||||
taskId: taskId.value,
|
||||
message: form.value.message
|
||||
message: form.value.message,
|
||||
messageType: ['1']
|
||||
});
|
||||
await proxy?.$modal.confirm('是否确认提交?');
|
||||
loading.value = true;
|
||||
|
||||
17
src/enums/NavTypeEnum.ts
Normal file
17
src/enums/NavTypeEnum.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 导航栏布局枚举
|
||||
*/
|
||||
export enum NavTypeEnum {
|
||||
/**
|
||||
* 左侧导航
|
||||
*/
|
||||
LEFT = 'left',
|
||||
/**
|
||||
* 顶部导航
|
||||
*/
|
||||
TOP = 'top',
|
||||
/**
|
||||
* 混合导航
|
||||
*/
|
||||
MIX = 'mix'
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<div class="navbar" :class="'nav' + navType">
|
||||
<hamburger id="hamburger-container" :is-active="appStore.sidebar.opened" class="hamburger-container" @toggle-click="toggleSideBar" />
|
||||
<breadcrumb v-if="!settingsStore.topNav" id="breadcrumb-container" class="breadcrumb-container" />
|
||||
<top-nav v-if="settingsStore.topNav" id="topmenu-container" class="topmenu-container" />
|
||||
|
||||
<breadcrumb v-if="navType == NavTypeEnum.LEFT" id="breadcrumb-container" class="breadcrumb-container" />
|
||||
<top-nav v-if="navType == NavTypeEnum.MIX" id="topmenu-container" class="topmenu-container" />
|
||||
|
||||
<template v-if="navType == NavTypeEnum.TOP">
|
||||
<logo v-show="showLogo" :collapse="false"></logo>
|
||||
<top-bar id="topbar-container" class="topbar-container" />
|
||||
</template>
|
||||
<div class="right-menu flex align-center">
|
||||
<template v-if="appStore.device !== 'mobile'">
|
||||
<el-select
|
||||
@@ -99,6 +104,9 @@ import { TenantVO } from '@/api/types';
|
||||
import notice from './notice/index.vue';
|
||||
import router from '@/router';
|
||||
import { ElMessageBoxOptions } from 'element-plus/es/components/message-box/src/message-box.type';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
import Logo from "@/layout/components/Sidebar/Logo.vue";
|
||||
import TopBar from './TopBar'
|
||||
|
||||
const appStore = useAppStore();
|
||||
const userStore = useUserStore();
|
||||
@@ -109,6 +117,9 @@ const newNotice = ref(<number>0);
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
const userId = ref(userStore.userId);
|
||||
const navType = computed(() => settingsStore.navType);
|
||||
const showLogo = computed(() => settingsStore.sidebarLogo);
|
||||
|
||||
const companyName = ref(undefined);
|
||||
const tenantList = ref<TenantVO[]>([]);
|
||||
// 是否切换了租户
|
||||
@@ -201,6 +212,12 @@ watch(
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar.navtop {
|
||||
.hamburger-container {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-select .el-input__wrapper) {
|
||||
height: 30px;
|
||||
}
|
||||
@@ -223,14 +240,22 @@ watch(
|
||||
position: relative;
|
||||
//background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// padding: 0 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
//float: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin-right: 8px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
@@ -238,7 +263,8 @@ watch(
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
//float: left;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.topmenu-container {
|
||||
@@ -246,16 +272,28 @@ watch(
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.topbar-container {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
|
||||
.errLog-container {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
//float: right;
|
||||
height: 100%;
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
<template>
|
||||
<el-drawer v-model="showSettings" :with-header="false" direction="rtl" size="300px" close-on-click-modal>
|
||||
<h3 class="drawer-title">菜单导航设置</h3>
|
||||
<div class="nav-wrap">
|
||||
<el-tooltip content="左侧菜单" placement="bottom">
|
||||
<div
|
||||
class="item left"
|
||||
@click="handleNavType(NavTypeEnum.LEFT)"
|
||||
:style="{ '--theme': theme }"
|
||||
:class="{ activeItem: navType == NavTypeEnum.LEFT }"
|
||||
>
|
||||
<b></b><b></b>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
<el-tooltip content="混合菜单" placement="bottom">
|
||||
<div
|
||||
class="item mix"
|
||||
@click="handleNavType(NavTypeEnum.MIX)"
|
||||
:style="{ '--theme': theme }"
|
||||
:class="{ activeItem: navType == NavTypeEnum.MIX }"
|
||||
>
|
||||
<b></b><b></b>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="顶部菜单" placement="bottom">
|
||||
<div
|
||||
class="item top"
|
||||
@click="handleNavType(NavTypeEnum.TOP)"
|
||||
:style="{ '--theme': theme }"
|
||||
:class="{ activeItem: navType == NavTypeEnum.TOP }"
|
||||
>
|
||||
<b></b><b></b>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<h3 class="drawer-title">主题风格设置</h3>
|
||||
|
||||
<div class="setting-drawer-block-checbox">
|
||||
@@ -45,13 +80,6 @@
|
||||
|
||||
<h3 class="drawer-title">系统布局配置</h3>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>开启 TopNav</span>
|
||||
<span class="comp-style">
|
||||
<el-switch v-model="settingsStore.topNav" class="drawer-switch" @change="topNavChange" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="drawer-item">
|
||||
<span>开启 Tags-Views</span>
|
||||
<span class="comp-style">
|
||||
@@ -101,6 +129,7 @@ import { useSettingsStore } from '@/store/modules/settings';
|
||||
import { usePermissionStore } from '@/store/modules/permission';
|
||||
import { handleThemeStyle } from '@/utils/theme';
|
||||
import { SideThemeEnum } from '@/enums/SideThemeEnum';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
import defaultSettings from '@/settings';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
@@ -113,7 +142,7 @@ 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']);
|
||||
|
||||
const navType = ref(settingsStore.navType);
|
||||
// 是否暗黑模式
|
||||
const isDark = useDark({
|
||||
storageKey: 'useDarkKey',
|
||||
@@ -130,11 +159,26 @@ watch(isDark, () => {
|
||||
});
|
||||
const toggleDark = () => useToggle(isDark);
|
||||
|
||||
const topNavChange = (val: any) => {
|
||||
if (!val) {
|
||||
appStore.toggleSideBarHide(false);
|
||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes as any);
|
||||
}
|
||||
/** 菜单导航设置 */
|
||||
watch(
|
||||
() => navType,
|
||||
(val: string) => {
|
||||
if (val.value === NavTypeEnum.TOP) {
|
||||
appStore.toggleSideBarHide(true);
|
||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes as any);
|
||||
} else if (val.value === NavTypeEnum.LEFT) {
|
||||
appStore.toggleSideBarHide(false);
|
||||
permissionStore.setSidebarRouters(permissionStore.defaultRoutes as any);
|
||||
} else if (val.value === NavTypeEnum.MIX) {
|
||||
appStore.toggleSideBarHide(false);
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
const handleNavType = (val: NavTypeEnum) => {
|
||||
settingsStore.navType = val;
|
||||
navType.value = val;
|
||||
};
|
||||
|
||||
const dynamicTitleChange = () => {
|
||||
@@ -158,7 +202,6 @@ const handleTheme = (val: string) => {
|
||||
const saveSetting = () => {
|
||||
proxy?.$modal.loading('正在保存到本地,请稍候...');
|
||||
const settings = useStorage<LayoutSetting>('layout-setting', defaultSettings);
|
||||
settings.value.topNav = storeSettings.value.topNav;
|
||||
settings.value.tagsView = storeSettings.value.tagsView;
|
||||
settings.value.tagsIcon = storeSettings.value.tagsIcon;
|
||||
settings.value.fixedHeader = storeSettings.value.fixedHeader;
|
||||
@@ -166,6 +209,7 @@ const saveSetting = () => {
|
||||
settings.value.dynamicTitle = storeSettings.value.dynamicTitle;
|
||||
settings.value.sideTheme = storeSettings.value.sideTheme;
|
||||
settings.value.theme = storeSettings.value.theme;
|
||||
settings.value.navType = storeSettings.value.navType;
|
||||
setTimeout(() => {
|
||||
proxy?.$modal.closeLoading();
|
||||
}, 1000);
|
||||
@@ -243,4 +287,67 @@ defineExpose({
|
||||
margin: -3px 8px 0px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
// 导航模式
|
||||
.nav-wrap {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.activeItem {
|
||||
border: 2px solid #{'var(--theme)'} !important;
|
||||
}
|
||||
|
||||
.item {
|
||||
position: relative;
|
||||
margin-right: 16px;
|
||||
cursor: pointer;
|
||||
width: 56px;
|
||||
height: 48px;
|
||||
border-radius: 4px;
|
||||
background: #f0f2f5;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
|
||||
.left {
|
||||
b:first-child {
|
||||
display: block;
|
||||
height: 30%;
|
||||
background: #fff;
|
||||
}
|
||||
b:last-child {
|
||||
width: 30%;
|
||||
background: #1b2a47;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
}
|
||||
.mix {
|
||||
b:first-child {
|
||||
border-radius: 4px 4px 0 0;
|
||||
display: block;
|
||||
height: 30%;
|
||||
background: #1b2a47;
|
||||
}
|
||||
b:last-child {
|
||||
width: 30%;
|
||||
background: #1b2a47;
|
||||
position: absolute;
|
||||
height: 70%;
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
}
|
||||
.top {
|
||||
b:first-child {
|
||||
display: block;
|
||||
height: 30%;
|
||||
background: #1b2a47;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
<div
|
||||
class="sidebar-logo-container"
|
||||
:class="{ collapse: collapse }"
|
||||
:style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }"
|
||||
>
|
||||
<transition :enter-active-class="proxy?.animate.logoAnimate.enter" mode="out-in">
|
||||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">
|
||||
<h1 v-else class="sidebar-title">
|
||||
{{ title }}
|
||||
</h1>
|
||||
</router-link>
|
||||
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
|
||||
<img v-if="logo" :src="logo" class="sidebar-logo" />
|
||||
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">
|
||||
<h1 class="sidebar-title">
|
||||
{{ title }}
|
||||
</h1>
|
||||
</router-link>
|
||||
@@ -26,6 +25,7 @@ import variables from '@/assets/styles/variables.module.scss';
|
||||
import logo from '@/assets/logo/logo.png';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
|
||||
defineProps({
|
||||
collapse: {
|
||||
@@ -37,6 +37,28 @@ defineProps({
|
||||
const title = import.meta.env.VITE_APP_LOGO_TITLE;
|
||||
const settingsStore = useSettingsStore();
|
||||
const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
|
||||
// 获取Logo背景色
|
||||
const getLogoBackground = computed(() => {
|
||||
if (settingsStore.isDark) {
|
||||
return 'var(--sidebar-bg)'
|
||||
}
|
||||
if (settingsStore.navType == NavTypeEnum.TOP) {
|
||||
return variables.menuLightBackground
|
||||
}
|
||||
return sideTheme.value === 'theme-dark' ? variables.menuBg : variables.menuLightBackground
|
||||
})
|
||||
|
||||
// 获取Logo文字颜色
|
||||
const getLogoTextColor = computed(() => {
|
||||
if (settingsStore.isDark) {
|
||||
return 'var(--sidebar-text)'
|
||||
}
|
||||
if (settingsStore.navType == NavTypeEnum.TOP) {
|
||||
return variables.logoLightTitleColor
|
||||
}
|
||||
return sideTheme.value === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -51,10 +73,9 @@ const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
|
||||
.sidebar-logo-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
background: #2b2f3a;
|
||||
background: v-bind(getLogoBackground);
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -67,21 +88,17 @@ const sideTheme = computed(() => settingsStore.sideTheme);
|
||||
height: 32px;
|
||||
vertical-align: middle;
|
||||
margin-right: 12px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
& .sidebar-title {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
color: #fff;
|
||||
color: v-bind(getLogoTextColor);
|
||||
font-weight: 600;
|
||||
line-height: 50px;
|
||||
font-size: 14px;
|
||||
font-family:
|
||||
Avenir,
|
||||
Helvetica Neue,
|
||||
Arial,
|
||||
Helvetica,
|
||||
sans-serif;
|
||||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
103
src/layout/components/TopBar/index.vue
Normal file
103
src/layout/components/TopBar/index.vue
Normal file
@@ -0,0 +1,103 @@
|
||||
<template>
|
||||
<el-menu class="topbar-menu" :ellipsis="false" :default-active="activeMenu" :active-text-color="theme" mode="horizontal">
|
||||
<sidebar-item :key="route.path + index" v-for="(route, index) in topMenus" :item="route" :base-path="route.path" />
|
||||
|
||||
<el-sub-menu index="more" class="el-sub-menu__hide-arrow" v-if="moreRoutes.length > 0">
|
||||
<template #title>
|
||||
<span>更多菜单</span>
|
||||
</template>
|
||||
<sidebar-item :key="route.path + index" v-for="(route, index) in moreRoutes" :item="route" :base-path="route.path" />
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import SidebarItem from '../Sidebar/SidebarItem'
|
||||
import {useAppStore} from '@/store/modules/app'
|
||||
import {useSettingsStore} from '@/store/modules/settings'
|
||||
import {usePermissionStore} from '@/store/modules/permission'
|
||||
|
||||
const route = useRoute()
|
||||
const appStore = useAppStore()
|
||||
const settingsStore = useSettingsStore()
|
||||
const permissionStore = usePermissionStore()
|
||||
|
||||
const sidebarRouters = computed(() => permissionStore.sidebarRouters)
|
||||
const theme = computed(() => settingsStore.theme)
|
||||
const device = computed(() => appStore.device)
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu
|
||||
}
|
||||
return path
|
||||
})
|
||||
|
||||
const visibleNumber = ref(5)
|
||||
const topMenus = computed(() => {
|
||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(0, visibleNumber.value)
|
||||
})
|
||||
const moreRoutes = computed(() => {
|
||||
return permissionStore.sidebarRouters.filter((f) => !f.hidden).slice(visibleNumber.value, sidebarRouters.value.length - visibleNumber.value)
|
||||
})
|
||||
function setVisibleNumber() {
|
||||
let width = document.body.getBoundingClientRect().width
|
||||
if (width >= 1000) {
|
||||
width -= 500
|
||||
}
|
||||
visibleNumber.value = parseInt(width / 3 / 85)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('resize', setVisibleNumber)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('resize', setVisibleNumber)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
setVisibleNumber()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
/* menu item */
|
||||
#app .topbar-menu.el-menu--horizontal .el-sub-menu__title, #app .topbar-menu.el-menu--horizontal .el-menu-item {
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
|
||||
.topbar-menu.el-menu--horizontal > .el-menu-item {
|
||||
float: left;
|
||||
height: 50px !important;
|
||||
line-height: 50px !important;
|
||||
color: #303133 !important;
|
||||
padding: 0 5px !important;
|
||||
margin: 0 10px !important;
|
||||
}
|
||||
|
||||
.el-sub-menu.is-active .svg-icon, .el-menu-item.is-active .svg-icon + span, .el-sub-menu.is-active .svg-icon + span, .el-sub-menu.is-active .el-sub-menu__title span {
|
||||
color: v-bind(theme);
|
||||
}
|
||||
|
||||
/* sub-menu item */
|
||||
.topbar-menu.el-menu--horizontal > .el-sub-menu .el-sub-menu__title {
|
||||
float: left;
|
||||
line-height: 50px !important;
|
||||
color: #303133 !important;
|
||||
margin: 0 15px -3px!important;
|
||||
}
|
||||
|
||||
/* topbar more arrow */
|
||||
.topbar-menu .el-sub-menu .el-sub-menu__icon-arrow {
|
||||
position: static;
|
||||
margin-left: 8px;
|
||||
margin-top: 0px;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* menu__title el-menu-item */
|
||||
.topbar-menu.el-menu--horizontal .el-sub-menu__title, .topbar-menu.el-menu--horizontal .el-menu-item {
|
||||
height: 60px;
|
||||
}
|
||||
</style>
|
||||
@@ -26,6 +26,7 @@ import SideBar from './components/Sidebar/index.vue';
|
||||
import { AppMain, Navbar, Settings, TagsView } from './components';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
import { initWebSocket } from '@/utils/websocket';
|
||||
import { initSSE } from '@/utils/sse';
|
||||
|
||||
@@ -35,6 +36,13 @@ const sidebar = computed(() => useAppStore().sidebar);
|
||||
const device = computed(() => useAppStore().device);
|
||||
const needTagsView = computed(() => settingsStore.tagsView);
|
||||
const fixedHeader = computed(() => settingsStore.fixedHeader);
|
||||
const layout = computed(() => settingsStore.navType);
|
||||
|
||||
// 根据布局模式判断是否显示侧边栏
|
||||
const showSidebar = computed(() => {
|
||||
if (sidebar.value.hide) return false;
|
||||
return layout.value === NavTypeEnum.LEFT || layout.value === NavTypeEnum.MIX;
|
||||
});
|
||||
|
||||
const classObj = computed(() => ({
|
||||
hideSidebar: !sidebar.value.opened,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { LanguageEnum } from '@/enums/LanguageEnum';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
|
||||
const setting: DefaultSettings = {
|
||||
/**
|
||||
@@ -18,9 +19,9 @@ const setting: DefaultSettings = {
|
||||
showSettings: true,
|
||||
|
||||
/**
|
||||
* 是否显示顶部导航
|
||||
* 默认布局
|
||||
*/
|
||||
topNav: false,
|
||||
navType: NavTypeEnum.LEFT,
|
||||
|
||||
/**
|
||||
* 是否显示 tagsView
|
||||
@@ -35,7 +36,7 @@ const setting: DefaultSettings = {
|
||||
/**
|
||||
* 是否固定头部
|
||||
*/
|
||||
fixedHeader: false,
|
||||
fixedHeader: true,
|
||||
|
||||
/**
|
||||
* 是否显示logo
|
||||
|
||||
@@ -3,6 +3,7 @@ import defaultSettings from '@/settings';
|
||||
import { useDynamicTitle } from '@/utils/dynamicTitle';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { ref } from 'vue';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
|
||||
export const useSettingsStore = defineStore('setting', () => {
|
||||
const storageSetting = useStorage<LayoutSetting>('layout-setting', {
|
||||
@@ -13,13 +14,13 @@ export const useSettingsStore = defineStore('setting', () => {
|
||||
sidebarLogo: defaultSettings.sidebarLogo,
|
||||
dynamicTitle: defaultSettings.dynamicTitle,
|
||||
sideTheme: defaultSettings.sideTheme,
|
||||
theme: defaultSettings.theme
|
||||
theme: defaultSettings.theme,
|
||||
navType: defaultSettings.navType
|
||||
});
|
||||
const title = ref<string>(defaultSettings.title);
|
||||
const theme = ref<string>(storageSetting.value.theme);
|
||||
const sideTheme = ref<string>(storageSetting.value.sideTheme);
|
||||
const showSettings = ref<boolean>(defaultSettings.showSettings);
|
||||
const topNav = ref<boolean>(storageSetting.value.topNav);
|
||||
const tagsView = ref<boolean>(storageSetting.value.tagsView);
|
||||
const tagsIcon = ref<boolean>(storageSetting.value.tagsIcon);
|
||||
const fixedHeader = ref<boolean>(storageSetting.value.fixedHeader);
|
||||
@@ -27,6 +28,7 @@ export const useSettingsStore = defineStore('setting', () => {
|
||||
const dynamicTitle = ref<boolean>(storageSetting.value.dynamicTitle);
|
||||
const animationEnable = ref<boolean>(defaultSettings.animationEnable);
|
||||
const dark = ref<boolean>(defaultSettings.dark);
|
||||
const navType = ref<NavTypeEnum>(storageSetting.value.navType || NavTypeEnum.LEFT);
|
||||
|
||||
const setTitle = (value: string) => {
|
||||
title.value = value;
|
||||
@@ -37,7 +39,6 @@ export const useSettingsStore = defineStore('setting', () => {
|
||||
theme,
|
||||
sideTheme,
|
||||
showSettings,
|
||||
topNav,
|
||||
tagsView,
|
||||
tagsIcon,
|
||||
fixedHeader,
|
||||
@@ -45,6 +46,7 @@ export const useSettingsStore = defineStore('setting', () => {
|
||||
dynamicTitle,
|
||||
animationEnable,
|
||||
dark,
|
||||
navType,
|
||||
setTitle
|
||||
};
|
||||
});
|
||||
|
||||
5
src/types/global.d.ts
vendored
5
src/types/global.d.ts
vendored
@@ -1,5 +1,6 @@
|
||||
import type { PropType as VuePropType, ComponentInternalInstance as ComponentInstance } from 'vue';
|
||||
import { LanguageEnum } from '@/enums/LanguageEnum';
|
||||
import { NavTypeEnum } from '@/enums/NavTypeEnum';
|
||||
|
||||
declare global {
|
||||
/** vue Instance */
|
||||
@@ -90,9 +91,9 @@ declare global {
|
||||
}
|
||||
declare interface LayoutSetting {
|
||||
/**
|
||||
* 是否显示顶部导航
|
||||
* 默认布局
|
||||
*/
|
||||
topNav: boolean;
|
||||
navType: NavTypeEnum;
|
||||
|
||||
/**
|
||||
* 是否显示多标签导航
|
||||
|
||||
@@ -86,12 +86,18 @@
|
||||
</el-card>
|
||||
<!-- 添加或修改参数配置对话框 -->
|
||||
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||
<el-form ref="dictFormRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form ref="dictFormRef" :model="form" :rules="rules" label-width="100px">
|
||||
<el-form-item label="字典名称" prop="dictName">
|
||||
<el-input v-model="form.dictName" placeholder="请输入字典名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="字典类型" prop="dictType">
|
||||
<el-input v-model="form.dictType" placeholder="请输入字典类型" />
|
||||
<el-form-item prop="dictType">
|
||||
<el-input v-model="form.dictType" placeholder="请输入字典类型" maxlength="100" />
|
||||
<span slot="label">
|
||||
<el-tooltip content="数据存储中的Key值,如:sys_user_sex" placement="top">
|
||||
<i class="el-icon-question"></i>
|
||||
</el-tooltip>
|
||||
字典类型
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||
|
||||
Reference in New Issue
Block a user