refactor(projects): 精简版+动态路由权限初步

This commit is contained in:
Soybean
2022-01-03 22:20:10 +08:00
parent 7a0648dba5
commit de2057f141
354 changed files with 2053 additions and 22117 deletions

View File

@ -1,26 +0,0 @@
<template>
<n-divider title-placement="center">深色主题</n-divider>
<div class="flex-center">
<n-switch :value="theme.darkMode" @update:value="handleDarkMode">
<template #checked>
<icon-mdi-white-balance-sunny class="text-14px text-primary" />
</template>
<template #unchecked>
<icon-mdi-moon-waning-crescent class="text-14px text-primary" />
</template>
</n-switch>
</div>
</template>
<script lang="ts" setup>
import { NDivider, NSwitch } from 'naive-ui';
import { useThemeStore } from '@/store';
const theme = useThemeStore();
const { handleDarkMode } = useThemeStore();
</script>
<style scoped>
:deep(.n-switch__rail) {
background-color: #000e1c !important;
}
</style>

View File

@ -1,26 +0,0 @@
<template>
<div
class="fixed flex-center top-240px right-14px z-10000 w-48px h-48px bg-primary rounded-4px cursor-pointer transition-right duration-300 ease-in-out"
:class="{ '!right-330px': app.settingDrawer.visible }"
@click="handleClickButton"
>
<icon-ic:round-close v-if="app.settingDrawer.visible" class="z-20 text-24px text-white" />
<icon-ic-round-settings v-else class="z-20 text-24px text-white" />
</div>
</template>
<script setup lang="ts">
import { useAppStore } from '@/store';
const app = useAppStore();
const { openSettingDrawer, closeSettingDrawer } = useAppStore();
function handleClickButton() {
if (app.settingDrawer.visible) {
closeSettingDrawer();
} else {
openSettingDrawer();
}
}
</script>
<style scoped></style>

View File

@ -1,59 +0,0 @@
<template>
<div
class="nav-type border-2px rounded-6px cursor-pointer"
:class="[checked ? 'border-primary' : 'border-transparent']"
>
<n-tooltip :placement="activeConfig.placement" trigger="hover">
<template #trigger>
<div class="nav-type-main relative w-56px h-48px bg-[#fff] rounded-4px overflow-hidden">
<div class="absolute-lt bg-[#273352]" :class="`${activeConfig.menuClass}`"></div>
<div class="absolute-rb bg-[#f0f2f5]" :class="`${activeConfig.mainClass}`"></div>
</div>
</template>
<span>{{ EnumNavMode[mode] }}</span>
</n-tooltip>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import { NTooltip } from 'naive-ui';
import type { FollowerPlacement } from 'vueuc';
import { EnumNavMode } from '@/enum';
import type { NavMode } from '@/interface';
interface Props {
/** 导航模式 */
mode?: NavMode;
/** 选中状态 */
checked?: boolean;
/** 主题颜色 */
primaryColor?: string;
}
const props = withDefaults(defineProps<Props>(), {
mode: 'vertical',
checked: false,
primaryColor: '#409EFF'
});
const config = new Map<NavMode, { placement: FollowerPlacement; menuClass: string; mainClass: string }>([
['vertical', { placement: 'bottom-start', menuClass: 'w-1/3 h-full', mainClass: 'w-2/3 h-3/4' }],
['vertical-mix', { placement: 'bottom', menuClass: 'w-1/4 h-full', mainClass: 'w-2/3 h-3/4' }],
['horizontal', { placement: 'bottom', menuClass: 'w-full h-1/4', mainClass: 'w-full h-3/4' }],
['horizontal-mix', { placement: 'bottom-end', menuClass: 'w-full h-1/4', mainClass: 'w-2/3 h-3/4' }]
]);
const activeConfig = computed(() => config.get(props.mode)!);
</script>
<style scoped>
.border-primary {
border-color: v-bind(primaryColor);
}
.nav-type:hover {
border-color: v-bind(primaryColor);
}
.nav-type-main {
box-shadow: 0 1px 2.5px rgba(0, 0, 0, 0.18);
}
</style>

View File

@ -1,3 +0,0 @@
import NavType from './NavType.vue';
export { NavType };

View File

@ -1,37 +0,0 @@
<template>
<n-divider title-placement="center">导航栏模式</n-divider>
<n-space justify="space-between">
<nav-type
v-for="item in modeList"
:key="item.mode"
:mode="item.mode"
:checked="theme.navStyle.mode === item.mode"
:primary-color="theme.themeColor"
@click="setNavMode(item.mode)"
/>
</n-space>
</template>
<script lang="ts" setup>
import { NDivider, NSpace } from 'naive-ui';
import { EnumNavMode } from '@/enum';
import type { NavMode } from '@/interface';
import { NavType } from './components';
import { useThemeStore } from '@/store';
interface ModeList {
mode: NavMode;
label: string;
}
const theme = useThemeStore();
const { setNavMode } = useThemeStore();
const modeList: ModeList[] = [
{ mode: 'vertical', label: EnumNavMode.vertical },
{ mode: 'vertical-mix', label: EnumNavMode['vertical-mix'] },
{ mode: 'horizontal', label: EnumNavMode.horizontal },
{ mode: 'horizontal-mix', label: EnumNavMode['horizontal-mix'] }
];
</script>
<style scoped></style>

View File

@ -1,102 +0,0 @@
<template>
<n-divider title-placement="center">界面功能</n-divider>
<n-space vertical size="large">
<setting-menu-item label="顶部菜单位置">
<n-select
class="w-120px"
size="small"
:value="theme.menuStyle.horizontalPosition"
:options="theme.menuStyle.horizontalPositionList"
@update:value="handleHorizontalMenuPosition"
/>
</setting-menu-item>
<setting-menu-item label="菜单展开宽度">
<n-input-number
class="w-120px"
size="small"
:value="theme.menuStyle.width"
:disabled="disabledMenuWidth"
:step="10"
@update:value="handleMenuWidth"
/>
</setting-menu-item>
<setting-menu-item label="左侧混合菜单展开宽度">
<n-input-number
class="w-120px"
size="small"
:value="theme.menuStyle.mixWidth"
:disabled="disabledMixMenuWidth"
:step="5"
@update:value="handleMixMenuWidth"
/>
</setting-menu-item>
<setting-menu-item label="固定头部和多页签">
<n-switch :value="theme.fixedHeaderAndTab" :disabled="isHorizontalMix" @update:value="handleFixedHeaderAndTab" />
</setting-menu-item>
<setting-menu-item label="头部高度">
<n-input-number
class="w-120px"
size="small"
:value="theme.headerStyle.height"
:step="1"
@update:value="handleHeaderHeight"
/>
</setting-menu-item>
<setting-menu-item label="多页签高度">
<n-input-number
class="w-120px"
size="small"
:value="theme.multiTabStyle.height"
:step="1"
@update:value="handleMultiTabHeight"
/>
</setting-menu-item>
<setting-menu-item label="多页签缓存">
<n-switch :value="theme.multiTabStyle.isCache" @update:value="handleSetMultiTabCache" />
</setting-menu-item>
<setting-menu-item label="清空多页签缓存">
<n-popconfirm placement="top-end" @positive-click="handleRemoveTabRouteCache">
<template #trigger>
<n-button type="primary" size="small">清空</n-button>
</template>
确定要清空多页签缓存吗
</n-popconfirm>
</setting-menu-item>
</n-space>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import { NDivider, NSpace, NSwitch, NSelect, NInputNumber, NButton, NPopconfirm, useMessage } from 'naive-ui';
import { useThemeStore, useAppStore } from '@/store';
import { clearTabRoutes } from '@/utils';
import { SettingMenuItem } from '../common';
const theme = useThemeStore();
const {
handleHorizontalMenuPosition,
handleFixedHeaderAndTab,
handleHeaderHeight,
handleMultiTabHeight,
handleMenuWidth,
handleMixMenuWidth,
handleSetMultiTabCache
} = useThemeStore();
const { initMultiTab } = useAppStore();
const message = useMessage();
const isHorizontalMix = computed(() => theme.navStyle.mode === 'horizontal-mix');
const disabledMenuWidth = computed(() => {
const { mode } = theme.navStyle;
return mode !== 'vertical' && mode !== 'horizontal-mix';
});
const disabledMixMenuWidth = computed(() => theme.navStyle.mode !== 'vertical-mix');
function handleRemoveTabRouteCache() {
clearTabRoutes();
initMultiTab();
message.success('操作成功!');
}
</script>
<style scoped></style>

View File

@ -1,52 +0,0 @@
<template>
<n-divider title-placement="center">界面显示</n-divider>
<n-space vertical size="large">
<setting-menu-item label="面包屑">
<n-switch :value="theme.crumbsStyle.visible" @update:value="handleCrumbsVisible" />
</setting-menu-item>
<setting-menu-item label="面包屑图标">
<n-switch :value="theme.crumbsStyle.showIcon" @update:value="handleCrumbsIconVisible" />
</setting-menu-item>
<setting-menu-item label="多页签">
<n-switch :value="theme.multiTabStyle.visible" @update:value="handleMultiTabVisible" />
</setting-menu-item>
<setting-menu-item label="多页签风格">
<n-select
class="w-120px"
size="small"
:value="theme.multiTabStyle.mode"
:options="theme.multiTabStyle.modeList"
@update:value="handleMultiTabMode"
/>
</setting-menu-item>
<setting-menu-item label="页面切换动画">
<n-switch :value="theme.pageStyle.animate" @update:value="handlePageAnimate" />
</setting-menu-item>
<setting-menu-item label="页面切换动画类型">
<n-select
class="w-120px"
size="small"
:value="theme.pageStyle.animateType"
:options="theme.pageStyle.animateTypeList"
@update:value="handlePageAnimateType"
/>
</setting-menu-item>
</n-space>
</template>
<script lang="ts" setup>
import { NDivider, NSpace, NSwitch, NSelect } from 'naive-ui';
import { useThemeStore } from '@/store';
import { SettingMenuItem } from '../common';
const theme = useThemeStore();
const {
handleCrumbsVisible,
handleCrumbsIconVisible,
handleMultiTabVisible,
handleMultiTabMode,
handlePageAnimate,
handlePageAnimateType
} = useThemeStore();
</script>
<style scoped></style>

View File

@ -1,18 +0,0 @@
<template>
<n-divider title-placement="center">系统主题</n-divider>
<n-grid :cols="8">
<n-grid-item v-for="color in theme.themeColorList" :key="color">
<color-block :color="color" :checked="color === theme.themeColor" @click="setThemeColor(color)" />
</n-grid-item>
</n-grid>
</template>
<script lang="ts" setup>
import { NDivider, NGrid, NGridItem } from 'naive-ui';
import { useThemeStore } from '@/store';
import { ColorBlock } from '../common';
const theme = useThemeStore();
const { setThemeColor } = useThemeStore();
</script>
<style scoped></style>

View File

@ -1,65 +0,0 @@
<template>
<n-divider title-placement="center">主题配置</n-divider>
<n-space vertical>
<div ref="copyRef" :data-clipboard-text="dataClipboardText">
<n-button type="primary" :block="true">拷贝当前配置</n-button>
</div>
<n-button type="warning" :block="true" @click="handleResetConfig">重置当前配置</n-button>
</n-space>
</template>
<script setup lang="ts">
import { ref, onMounted, watch } from 'vue';
import { NDivider, NSpace, NButton, useDialog, useMessage } from 'naive-ui';
import Clipboard from 'clipboard';
import { useThemeStore } from '@/store';
const theme = useThemeStore();
const { setDefaultThemeStore } = useThemeStore();
const dialog = useDialog();
const message = useMessage();
const copyRef = ref<HTMLElement | null>(null);
const dataClipboardText = ref(getClipboardText());
function getClipboardText() {
return JSON.stringify(theme.$state);
}
function handleResetConfig() {
setDefaultThemeStore();
message.success('已重置配置,请重新拷贝!');
}
function clipboardEventListener() {
const copy = new Clipboard(copyRef.value!);
copy.on('success', () => {
dialog.success({
title: '操作成功',
content: '复制成功,请替换 src/settings/theme.json的内容',
positiveText: '确定'
});
});
}
watch(
() => theme.$state,
() => {
dataClipboardText.value = getClipboardText();
},
{ deep: true }
);
onMounted(() => {
clipboardEventListener();
});
// function handleSuccess() {
// window.$dialog?.success({
// title: '操作成功',
// content: '复制成功,请替换 src/settings/theme.json的内容',
// positiveText: '确定'
// });
// }
</script>
<style scoped></style>

View File

@ -1,26 +0,0 @@
<template>
<div class="flex-center w-20px h-20px mx-6px mb-8px cursor-pointer rounded-2px" :style="{ backgroundColor: color }">
<icon-ic-outline-check
v-if="checked"
class="text-14px text-white"
:class="[isWhite ? 'text-gray-700' : 'text-white']"
/>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
interface Props {
color: string;
checked?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
checked: false
});
const whiteColors = ['#ffffff', '#fff', 'rgb(255,255,255)'];
const isWhite = computed(() => whiteColors.includes(props.color));
</script>
<style scoped></style>

View File

@ -1,16 +0,0 @@
<template>
<div class="flex-y-center justify-between">
<span>{{ label }}</span>
<slot></slot>
</div>
</template>
<script lang="ts" setup>
interface Props {
/** 文本 */
label: string;
}
defineProps<Props>();
</script>
<style scoped></style>

View File

@ -1,4 +0,0 @@
import ColorBlock from './ColorBlock.vue';
import SettingMenuItem from './SettingMenuItem.vue';
export { ColorBlock, SettingMenuItem };

View File

@ -1,9 +0,0 @@
import DarkMode from './DarkMode/index.vue';
import NavMode from './NavMode/index.vue';
import SystemTheme from './SystemTheme/index.vue';
import PageFunc from './PageFunc/index.vue';
import PageView from './PageView/index.vue';
import ThemeConfig from './ThemeConfig/index.vue';
import DrawerButton from './DrawerButton/index.vue';
export { DarkMode, NavMode, SystemTheme, PageFunc, PageView, ThemeConfig, DrawerButton };

View File

@ -1,24 +0,0 @@
<template>
<n-drawer v-model:show="app.settingDrawer.visible" display-directive="show" :width="330">
<n-drawer-content title="主题配置" :native-scrollbar="false">
<dark-mode />
<nav-mode />
<system-theme />
<page-func />
<page-view />
<theme-config />
</n-drawer-content>
</n-drawer>
<drawer-button v-if="showSettingButton" />
</template>
<script lang="ts" setup>
import { NDrawer, NDrawerContent } from 'naive-ui';
import { useAppStore } from '@/store';
import { DarkMode, NavMode, SystemTheme, PageFunc, PageView, ThemeConfig, DrawerButton } from './components';
const app = useAppStore();
const showSettingButton = import.meta.env.DEV || import.meta.env.VITE_HTTP_ENV === 'STAGING';
</script>
<style scoped></style>