mirror of
https://github.com/vbenjs/vben-admin-thin-next.git
synced 2025-01-23 09:40:22 +08:00
feat: add useDesign
This commit is contained in:
parent
bd6b203fa9
commit
74e62cbc71
@ -3,6 +3,7 @@ ls:
|
||||
.js: kebab-case | PascalCase
|
||||
.vue: PascalCase | regex:^index
|
||||
.ts: camelCase | PascalCase
|
||||
.tsx: camelCase | PascalCase
|
||||
.d.ts: kebab-case
|
||||
.mock.ts: kebab-case
|
||||
.data.ts: camelCase | kebab-case
|
||||
|
@ -4,7 +4,9 @@
|
||||
:locale="antConfigLocale"
|
||||
:transform-cell-text="transformCellText"
|
||||
>
|
||||
<router-view />
|
||||
<AppProvider>
|
||||
<router-view />
|
||||
</AppProvider>
|
||||
</ConfigProvider>
|
||||
</template>
|
||||
|
||||
@ -17,9 +19,11 @@
|
||||
import { useLockPage } from '/@/hooks/web/useLockPage';
|
||||
import { useLocale } from '/@/hooks/web/useLocale';
|
||||
|
||||
import { AppProvider } from '/@/components/Application';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
components: { ConfigProvider },
|
||||
components: { ConfigProvider, AppProvider },
|
||||
setup() {
|
||||
// Initialize vuex internal system configuration
|
||||
initAppConfigStore();
|
||||
|
@ -1,6 +1,10 @@
|
||||
import AppLocalePickerLib from './src/AppLocalePicker.vue';
|
||||
import AppLogoLib from './src/AppLogo.vue';
|
||||
import AppLocalePicker from './src/AppLocalePicker.vue';
|
||||
import AppLogo from './src/AppLogo.vue';
|
||||
import AppProvider from './src/AppProvider.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const AppLocalePicker = withInstall(AppLocalePickerLib);
|
||||
export const AppLogo = withInstall(AppLogoLib);
|
||||
withInstall(AppLocalePicker, AppLogo, AppProvider);
|
||||
|
||||
export { useAppProviderContext } from './src/useAppContext';
|
||||
|
||||
export { AppLocalePicker, AppLogo, AppProvider };
|
||||
|
@ -69,8 +69,8 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.app-locale-picker-overlay {
|
||||
<style lang="less" scoped>
|
||||
:global(.app-locale-picker-overlay) {
|
||||
.ant-dropdown-menu-item {
|
||||
min-width: 160px;
|
||||
}
|
||||
|
@ -4,12 +4,14 @@
|
||||
-->
|
||||
<template>
|
||||
<div
|
||||
class="app-logo anticon"
|
||||
:class="{ theme, 'collapsed-show-title': getCollapsedShowTitle }"
|
||||
class="anticon"
|
||||
:class="[prefixCls, theme, { 'collapsed-show-title': getCollapsedShowTitle }]"
|
||||
@click="handleGoHome"
|
||||
>
|
||||
<img src="/@/assets/images/logo.png" />
|
||||
<div class="app-logo__title ml-2 ellipsis" v-show="showTitle">{{ globSetting.title }}</div>
|
||||
<div class="ml-2 ellipsis" :class="[`${prefixCls}__title`]" v-show="showTitle">
|
||||
{{ globSetting.title }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
@ -23,6 +25,8 @@
|
||||
|
||||
import { propTypes } from '/@/utils/propTypes';
|
||||
|
||||
import { useDesign } from '/@/hooks/web/useDesign';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AppLogo',
|
||||
props: {
|
||||
@ -34,6 +38,8 @@
|
||||
showTitle: propTypes.bool.def(true),
|
||||
},
|
||||
setup() {
|
||||
const { prefixCls } = useDesign('app-logo');
|
||||
|
||||
const { getCollapsedShowTitle } = useMenuSetting();
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
@ -48,17 +54,19 @@
|
||||
handleGoHome,
|
||||
globSetting,
|
||||
getCollapsedShowTitle,
|
||||
prefixCls,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
@import (reference) '../../../design/index.less';
|
||||
@prefix-cls: ~'@{namespace}-app-logo';
|
||||
|
||||
.app-logo {
|
||||
.@{prefix-cls} {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 10px;
|
||||
padding-left: 12px;
|
||||
cursor: pointer;
|
||||
|
||||
&.collapsed-show-title {
|
||||
|
24
src/components/Application/src/AppProvider.vue
Normal file
24
src/components/Application/src/AppProvider.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<slot />
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import { defineComponent, toRefs } from 'vue';
|
||||
|
||||
import { createAppProviderContext } from './useAppContext';
|
||||
export default defineComponent({
|
||||
name: 'AppProvider',
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
prefixCls: {
|
||||
type: String as PropType<string>,
|
||||
default: 'vben',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { prefixCls } = toRefs(props);
|
||||
createAppProviderContext({ prefixCls });
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
16
src/components/Application/src/useAppContext.ts
Normal file
16
src/components/Application/src/useAppContext.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { InjectionKey, Ref } from 'vue';
|
||||
import { createContext, useContext } from '/@/hooks/core/useContext';
|
||||
|
||||
export interface AppProviderContextProps {
|
||||
prefixCls: Ref<string>;
|
||||
}
|
||||
|
||||
const key: InjectionKey<AppProviderContextProps> = Symbol();
|
||||
|
||||
export function createAppProviderContext(context: AppProviderContextProps) {
|
||||
return createContext<AppProviderContextProps>(context, key);
|
||||
}
|
||||
|
||||
export function useAppProviderContext() {
|
||||
return useContext<AppProviderContextProps>(key);
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
import AuthorityLib from './src/index.vue';
|
||||
import Authority from './src/index.vue';
|
||||
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const Authority = withInstall(AuthorityLib);
|
||||
withInstall(Authority);
|
||||
|
||||
export { Authority };
|
||||
|
@ -1,9 +1,9 @@
|
||||
import BasicArrowLib from './src/BasicArrow.vue';
|
||||
import BasicHelpLib from './src/BasicHelp.vue';
|
||||
import BasicTitleLib from './src/BasicTitle.vue';
|
||||
import BasicArrow from './src/BasicArrow.vue';
|
||||
import BasicHelp from './src/BasicHelp.vue';
|
||||
import BasicTitle from './src/BasicTitle.vue';
|
||||
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const BasicArrow = withInstall(BasicArrowLib);
|
||||
export const BasicHelp = withInstall(BasicHelpLib);
|
||||
export const BasicTitle = withInstall(BasicTitleLib);
|
||||
withInstall(BasicArrow, BasicHelp, BasicTitle);
|
||||
|
||||
export { BasicArrow, BasicHelp, BasicTitle };
|
||||
|
@ -1,4 +1,6 @@
|
||||
import ButtonLib from './src/BasicButton.vue';
|
||||
import Button from './src/BasicButton.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const Button = withInstall(ButtonLib);
|
||||
withInstall(Button);
|
||||
|
||||
export { Button };
|
||||
|
@ -1,4 +1,6 @@
|
||||
import ClickOutSideLib from './src/index.vue';
|
||||
import ClickOutSide from './src/index.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const ClickOutSide = withInstall(ClickOutSideLib);
|
||||
withInstall(ClickOutSide);
|
||||
|
||||
export { ClickOutSide };
|
||||
|
@ -1,10 +1,10 @@
|
||||
import ScrollContainerLib from './src/ScrollContainer.vue';
|
||||
import CollapseContainerLib from './src/collapse/CollapseContainer.vue';
|
||||
import LazyContainerLib from './src/LazyContainer.vue';
|
||||
import ScrollContainer from './src/ScrollContainer.vue';
|
||||
import CollapseContainer from './src/collapse/CollapseContainer.vue';
|
||||
import LazyContainer from './src/LazyContainer.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(ScrollContainer, CollapseContainer, LazyContainer);
|
||||
|
||||
export * from './src/types';
|
||||
|
||||
export const ScrollContainer = withInstall(ScrollContainerLib);
|
||||
export const CollapseContainer = withInstall(CollapseContainerLib);
|
||||
export const LazyContainer = withInstall(LazyContainerLib);
|
||||
export { ScrollContainer, CollapseContainer, LazyContainer };
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Transform vue-count-to to support vue3 version
|
||||
|
||||
import CountToLib from './src/index.vue';
|
||||
import CountTo from './src/index.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const CountTo = withInstall(CountToLib);
|
||||
withInstall(CountTo);
|
||||
export { CountTo };
|
||||
|
@ -1,8 +1,9 @@
|
||||
import DescriptionLib from './src/index';
|
||||
import Description from './src/index';
|
||||
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(Description);
|
||||
|
||||
export * from './src/types';
|
||||
export { useDescription } from './src/useDescription';
|
||||
|
||||
export const Description = withInstall(DescriptionLib);
|
||||
export { Description };
|
||||
|
@ -1,6 +1,7 @@
|
||||
import BasicDrawerLib from './src/BasicDrawer';
|
||||
import BasicDrawer from './src/BasicDrawer';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(BasicDrawer);
|
||||
export * from './src/types';
|
||||
export { useDrawer, useDrawerInner } from './src/useDrawer';
|
||||
export const BasicDrawer = withInstall(BasicDrawerLib);
|
||||
export { BasicDrawer };
|
||||
|
@ -1,6 +1,7 @@
|
||||
import DropdownLib from './src/Dropdown';
|
||||
import Dropdown from './src/Dropdown';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(Dropdown);
|
||||
export * from './src/types';
|
||||
|
||||
export const Dropdown = withInstall(DropdownLib);
|
||||
export { Dropdown };
|
||||
|
@ -1,11 +1,12 @@
|
||||
import ImportExcelLib from './src/ImportExcel.vue';
|
||||
import ExportExcelModelLib from './src/ExportExcelModel.vue';
|
||||
import ImportExcel from './src/ImportExcel.vue';
|
||||
import ExportExcelModel from './src/ExportExcelModel.vue';
|
||||
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(ImportExcel, ExportExcelModel);
|
||||
|
||||
export * from './src/types';
|
||||
|
||||
export { jsonToSheetXlsx, aoaToSheetXlsx } from './src/Export2Excel';
|
||||
|
||||
export const ImportExcel = withInstall(ImportExcelLib);
|
||||
export const ExportExcelModel = withInstall(ExportExcelModelLib);
|
||||
export { ImportExcel, ExportExcelModel };
|
||||
|
@ -1,10 +1,12 @@
|
||||
import BasicFormLib from './src/BasicForm.vue';
|
||||
import BasicForm from './src/BasicForm.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(BasicForm);
|
||||
|
||||
export * from './src/types/form';
|
||||
export * from './src/types/formItem';
|
||||
|
||||
export { useComponentRegister } from './src/hooks/useComponentRegister';
|
||||
export { useForm } from './src/hooks/useForm';
|
||||
|
||||
export const BasicForm = withInstall(BasicFormLib);
|
||||
export { BasicForm };
|
||||
|
@ -1,8 +1,9 @@
|
||||
import './src/indicator';
|
||||
import LoadingLib from './src/index.vue';
|
||||
import Loading from './src/index.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(Loading);
|
||||
export { useLoading } from './src/useLoading';
|
||||
export { createLoading } from './src/createLoading';
|
||||
|
||||
export const Loading = withInstall(LoadingLib);
|
||||
export { Loading };
|
||||
|
@ -1,7 +1,9 @@
|
||||
import MarkDownLib from './src/index.vue';
|
||||
import MarkDown from './src/index.vue';
|
||||
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(MarkDown);
|
||||
|
||||
export * from './src/types';
|
||||
|
||||
export const MarkDown = withInstall(MarkDownLib);
|
||||
export { MarkDown };
|
||||
|
@ -1,4 +1,5 @@
|
||||
import BasicMenuLib from './src/BasicMenu';
|
||||
import BasicMenu from './src/BasicMenu';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const BasicMenu = withInstall(BasicMenuLib);
|
||||
withInstall(BasicMenu);
|
||||
export { BasicMenu };
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
ComputedRef,
|
||||
} from 'vue';
|
||||
import { Menu } from 'ant-design-vue';
|
||||
import SearchInput from './SearchInput.vue';
|
||||
import MenuContent from './MenuContent';
|
||||
// import { ScrollContainer } from '/@/components/Container';
|
||||
|
||||
@ -24,8 +23,7 @@ import { ThemeEnum } from '/@/enums/appEnum';
|
||||
|
||||
import { appStore } from '/@/store/modules/app';
|
||||
|
||||
import { useSearchInput } from './hooks/useSearchInput';
|
||||
import { useOpenKeys } from './hooks/useOpenKeys';
|
||||
import { useOpenKeys } from './useOpenKeys';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { isFunction } from '/@/utils/is';
|
||||
@ -43,51 +41,39 @@ export default defineComponent({
|
||||
emits: ['menuClick'],
|
||||
setup(props, { slots, emit }) {
|
||||
const currentParentPath = ref('');
|
||||
|
||||
const menuState = reactive<MenuState>({
|
||||
defaultSelectedKeys: [],
|
||||
mode: props.mode,
|
||||
theme: computed(() => props.theme) as ComputedRef<ThemeEnum>,
|
||||
openKeys: [],
|
||||
searchValue: '',
|
||||
selectedKeys: [],
|
||||
collapsedOpenKeys: [],
|
||||
});
|
||||
|
||||
const { getCollapsed } = useMenuSetting();
|
||||
|
||||
const { currentRoute } = useRouter();
|
||||
|
||||
const { items, flatItems, isAppMenu, mode, accordion } = toRefs(props);
|
||||
|
||||
const { handleInputChange, handleInputClick } = useSearchInput({
|
||||
flatMenusRef: flatItems,
|
||||
emit: emit,
|
||||
menuState,
|
||||
handleMenuChange,
|
||||
});
|
||||
const { items, flatItems, mode, accordion } = toRefs(props);
|
||||
|
||||
const { handleOpenChange, resetKeys, setOpenKeys } = useOpenKeys(
|
||||
menuState,
|
||||
items,
|
||||
flatItems,
|
||||
isAppMenu,
|
||||
mode,
|
||||
accordion
|
||||
);
|
||||
|
||||
const getOpenKeys = computed(() => {
|
||||
if (props.isAppMenu) {
|
||||
return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys;
|
||||
}
|
||||
return menuState.openKeys;
|
||||
return unref(getCollapsed) ? menuState.collapsedOpenKeys : menuState.openKeys;
|
||||
});
|
||||
|
||||
// menu外层样式
|
||||
const getMenuWrapStyle = computed((): any => {
|
||||
const { showLogo, search } = props;
|
||||
const { showLogo } = props;
|
||||
let offset = 0;
|
||||
if (search) {
|
||||
offset += 54;
|
||||
}
|
||||
|
||||
if (showLogo) {
|
||||
offset += 46;
|
||||
}
|
||||
@ -110,7 +96,7 @@ export default defineComponent({
|
||||
cls.push('basic-menu__sidebar-hor');
|
||||
}
|
||||
|
||||
if (!props.isHorizontal && props.isAppMenu && appStore.getProjectConfig.menuSetting.split) {
|
||||
if (!props.isHorizontal && appStore.getProjectConfig.menuSetting.split) {
|
||||
cls.push('basic-menu__second');
|
||||
}
|
||||
return cls;
|
||||
@ -197,7 +183,6 @@ export default defineComponent({
|
||||
level={index}
|
||||
isHorizontal={props.isHorizontal}
|
||||
showTitle={unref(showTitle)}
|
||||
searchValue={menuState.searchValue}
|
||||
/>,
|
||||
]}
|
||||
</Menu.Item>
|
||||
@ -212,7 +197,6 @@ export default defineComponent({
|
||||
item={menu}
|
||||
level={index}
|
||||
isHorizontal={props.isHorizontal}
|
||||
searchValue={menuState.searchValue}
|
||||
/>,
|
||||
],
|
||||
default: () => renderMenuItem(menu.children, index + 1),
|
||||
@ -227,11 +211,9 @@ export default defineComponent({
|
||||
const { selectedKeys, defaultSelectedKeys, mode, theme } = menuState;
|
||||
|
||||
const inlineCollapsedObj = isInline
|
||||
? props.isAppMenu
|
||||
? {
|
||||
inlineCollapsed: unref(getCollapsed),
|
||||
}
|
||||
: { inlineCollapsed: props.inlineCollapsed }
|
||||
? {
|
||||
inlineCollapsed: unref(getCollapsed),
|
||||
}
|
||||
: {};
|
||||
return (
|
||||
<Menu
|
||||
@ -267,17 +249,8 @@ export default defineComponent({
|
||||
) : (
|
||||
<section class={[`basic-menu-wrap`, !unref(showTitle) && 'hide-title']}>
|
||||
{getSlot(slots, 'header')}
|
||||
<SearchInput
|
||||
class={!props.search ? 'hidden' : ''}
|
||||
theme={props.theme as ThemeEnum}
|
||||
onChange={handleInputChange}
|
||||
onClick={handleInputClick}
|
||||
collapsed={unref(getCollapsed)}
|
||||
/>
|
||||
|
||||
{/* <section style={unref(getMenuWrapStyle)}> */}
|
||||
<section style={unref(getMenuWrapStyle)} class="basic-menu__content">
|
||||
{/* <ScrollContainer>{() => renderMenu()}</ScrollContainer> */}
|
||||
{renderMenu()}
|
||||
</section>
|
||||
</section>
|
||||
|
11
src/components/Menu/src/BasicMenu.vue
Normal file
11
src/components/Menu/src/BasicMenu.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div> </div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
@ -8,11 +8,6 @@ import { useI18n } from '/@/hooks/web/useI18n';
|
||||
export default defineComponent({
|
||||
name: 'MenuContent',
|
||||
props: {
|
||||
searchValue: {
|
||||
type: String as PropType<string>,
|
||||
default: '',
|
||||
},
|
||||
|
||||
item: {
|
||||
type: Object as PropType<MenuType>,
|
||||
default: null,
|
||||
@ -35,11 +30,7 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const getI18nName = computed(() => {
|
||||
const { name } = props.item;
|
||||
|
||||
return t(name);
|
||||
});
|
||||
const getI18nName = computed(() => t(props.item?.name));
|
||||
/**
|
||||
* @description: 渲染图标
|
||||
*/
|
||||
@ -71,28 +62,18 @@ export default defineComponent({
|
||||
const { showTitle } = props;
|
||||
const { icon } = props.item;
|
||||
const name = unref(getI18nName);
|
||||
const searchValue = props.searchValue || '';
|
||||
const index = name.indexOf(searchValue);
|
||||
|
||||
const beforeStr = name.substr(0, index);
|
||||
const afterStr = name.substr(index + searchValue.length);
|
||||
const cls = showTitle ? ['show-title'] : ['basic-menu__name'];
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderIcon(icon!)}
|
||||
{index > -1 && searchValue ? (
|
||||
<span class={cls}>
|
||||
{beforeStr}
|
||||
<span class={`basic-menu__keyword`}>{searchValue}</span>
|
||||
{afterStr}
|
||||
</span>
|
||||
) : (
|
||||
{
|
||||
<span class={[cls]}>
|
||||
{name}
|
||||
{renderTag()}
|
||||
</span>
|
||||
)}
|
||||
}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,116 +0,0 @@
|
||||
<template>
|
||||
<section class="menu-search-input" @Click="handleClick" :class="searchClass">
|
||||
<a-input-search
|
||||
:placeholder="t('component.menu.search')"
|
||||
class="menu-search-input__search"
|
||||
allowClear
|
||||
@change="handleChange"
|
||||
/>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { PropType } from 'vue';
|
||||
import { defineComponent, computed } from 'vue';
|
||||
import { ThemeEnum } from '/@/enums/appEnum';
|
||||
// hook
|
||||
import { useDebounce } from '/@/hooks/core/useDebounce';
|
||||
import { useI18n } from '/@/hooks/web/useI18n';
|
||||
//
|
||||
export default defineComponent({
|
||||
name: 'BasicMenuSearchInput',
|
||||
props: {
|
||||
// Whether to expand, used in the left menu
|
||||
collapsed: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
theme: {
|
||||
type: String as PropType<ThemeEnum>,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { t } = useI18n();
|
||||
|
||||
const [debounceEmitChange] = useDebounce(emitChange, 200);
|
||||
|
||||
function emitChange(value?: string): void {
|
||||
emit('change', value);
|
||||
}
|
||||
|
||||
function handleChange(e: ChangeEvent): void {
|
||||
const { collapsed } = props;
|
||||
if (collapsed) return;
|
||||
debounceEmitChange(e.target.value);
|
||||
}
|
||||
|
||||
function handleClick(): void {
|
||||
emit('click');
|
||||
}
|
||||
|
||||
const searchClass = computed(() => {
|
||||
const cls: string[] = [];
|
||||
cls.push(props.theme ? `menu-search-input__search--${props.theme}` : '');
|
||||
cls.push(props.collapsed ? 'hide-search-icon' : '');
|
||||
return cls;
|
||||
});
|
||||
|
||||
return { handleClick, searchClass, handleChange, t };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
@import (reference) '../../../design/index.less';
|
||||
// 输入框背景颜色 深
|
||||
@input-dark-bg-color: #516085;
|
||||
|
||||
@icon-color: #c0c4cc;
|
||||
|
||||
.menu-search-input {
|
||||
margin: 12px 8px;
|
||||
|
||||
&.hide-search-icon {
|
||||
.ant-input,
|
||||
.ant-input-suffix {
|
||||
opacity: 0;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
}
|
||||
|
||||
&__search--dark {
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-input {
|
||||
.set-bg();
|
||||
}
|
||||
|
||||
.ant-input-search-icon,
|
||||
.ant-input-clear-icon {
|
||||
color: rgba(255, 255, 255, 0.4) !important;
|
||||
}
|
||||
}
|
||||
|
||||
&__search--light {
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-input {
|
||||
color: @text-color-base;
|
||||
background: #fff;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ant-input-search-icon {
|
||||
color: @icon-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.set-bg() {
|
||||
color: #fff;
|
||||
background: @sider-dark-lighten-1-bg-color;
|
||||
border: 0;
|
||||
outline: none;
|
||||
}
|
||||
.hide-outline() {
|
||||
border: none;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
</style>
|
@ -1,58 +0,0 @@
|
||||
import type { Menu as MenuType } from '/@/router/types';
|
||||
import type { MenuState } from '../types';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { isString } from '/@/utils/is';
|
||||
import { unref } from 'vue';
|
||||
import { es6Unique } from '/@/utils';
|
||||
import { getAllParentPath } from '/@/router/helper/menuHelper';
|
||||
|
||||
interface UseSearchInputOptions {
|
||||
menuState: MenuState;
|
||||
flatMenusRef: Ref<MenuType[]>;
|
||||
emit: EmitType;
|
||||
handleMenuChange: Fn;
|
||||
}
|
||||
export function useSearchInput({
|
||||
menuState,
|
||||
flatMenusRef,
|
||||
handleMenuChange,
|
||||
emit,
|
||||
}: UseSearchInputOptions) {
|
||||
/**
|
||||
* @description: 输入框搜索
|
||||
*/
|
||||
function handleInputChange(value?: string): void {
|
||||
if (!isString(value)) {
|
||||
value = (value as any).target.value;
|
||||
}
|
||||
if (!value) {
|
||||
handleMenuChange && handleMenuChange();
|
||||
}
|
||||
|
||||
menuState.searchValue = value || '';
|
||||
if (!value) {
|
||||
menuState.openKeys = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const flatMenus = unref(flatMenusRef);
|
||||
let openKeys: string[] = [];
|
||||
for (const menu of flatMenus) {
|
||||
const { name, path } = menu;
|
||||
if (!name.includes(value)) {
|
||||
continue;
|
||||
}
|
||||
openKeys = openKeys.concat(getAllParentPath(flatMenus, path));
|
||||
}
|
||||
openKeys = es6Unique(openKeys);
|
||||
menuState.openKeys = openKeys;
|
||||
}
|
||||
|
||||
// 搜索框点击
|
||||
function handleInputClick(e: any): void {
|
||||
emit('clickSearchInput', e);
|
||||
}
|
||||
|
||||
return { handleInputChange, handleInputClick };
|
||||
}
|
@ -20,11 +20,7 @@ export const basicProps = {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
// 是否显示搜索框
|
||||
search: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
|
||||
// 最好是4 倍数
|
||||
inlineIndent: {
|
||||
type: Number as PropType<number>,
|
||||
@ -51,10 +47,7 @@ export const basicProps = {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
},
|
||||
isAppMenu: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true,
|
||||
},
|
||||
|
||||
isHorizontal: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false,
|
||||
|
@ -17,9 +17,6 @@ export interface MenuState {
|
||||
// 展开数组
|
||||
openKeys: string[];
|
||||
|
||||
// 搜索值
|
||||
searchValue: string;
|
||||
|
||||
// 当前选中的菜单项 key 数组
|
||||
selectedKeys: string[];
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { MenuModeEnum } from '/@/enums/menuEnum';
|
||||
import type { Menu as MenuType } from '/@/router/types';
|
||||
import type { MenuState } from '../types';
|
||||
import type { MenuState } from './types';
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { unref } from 'vue';
|
||||
@ -12,14 +12,11 @@ export function useOpenKeys(
|
||||
menuState: MenuState,
|
||||
menus: Ref<MenuType[]>,
|
||||
flatMenusRef: Ref<MenuType[]>,
|
||||
isAppMenu: Ref<boolean>,
|
||||
mode: Ref<MenuModeEnum>,
|
||||
accordion: Ref<boolean>
|
||||
) {
|
||||
const { getCollapsed } = useMenuSetting();
|
||||
/**
|
||||
* @description:设置展开
|
||||
*/
|
||||
|
||||
function setOpenKeys(menu: MenuType) {
|
||||
const flatMenus = unref(flatMenusRef);
|
||||
if (!unref(accordion)) {
|
||||
@ -50,7 +47,7 @@ export function useOpenKeys(
|
||||
rootSubMenuKeys.push(path);
|
||||
}
|
||||
}
|
||||
if (!unref(getCollapsed) || !unref(isAppMenu)) {
|
||||
if (!unref(getCollapsed)) {
|
||||
const latestOpenKey = openKeys.find((key) => menuState.openKeys.indexOf(key) === -1);
|
||||
if (rootSubMenuKeys.indexOf(latestOpenKey as string) === -1) {
|
||||
menuState.openKeys = openKeys;
|
@ -1,8 +1,10 @@
|
||||
import './src/index.less';
|
||||
import BasicModalLib from './src/BasicModal';
|
||||
import BasicModal from './src/BasicModal';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(BasicModal);
|
||||
|
||||
export { useModalContext } from './src/useModalContext';
|
||||
export { useModal, useModalInner } from './src/useModal';
|
||||
export * from './src/types';
|
||||
export const BasicModal = withInstall(BasicModalLib);
|
||||
export { BasicModal };
|
||||
|
@ -1,4 +1,5 @@
|
||||
import PageFooterLib from './src/PageFooter.vue';
|
||||
import PageFooter from './src/PageFooter.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const PageFooter = withInstall(PageFooterLib);
|
||||
withInstall(PageFooter);
|
||||
export { PageFooter };
|
||||
|
@ -1,4 +1,5 @@
|
||||
import StrengthMeterLib from './src/index';
|
||||
import StrengthMeter from './src/index';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const StrengthMeter = withInstall(StrengthMeterLib);
|
||||
withInstall(StrengthMeter);
|
||||
export { StrengthMeter };
|
||||
|
@ -1,4 +1,5 @@
|
||||
import TinymceLib from './src/Editor.vue';
|
||||
import Tinymce from './src/Editor.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const Tinymce = withInstall(TinymceLib);
|
||||
withInstall(Tinymce);
|
||||
export { Tinymce };
|
||||
|
@ -1,8 +1,5 @@
|
||||
import type { App } from 'vue';
|
||||
import BasicUpload from './src/BasicUpload.vue';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export default (app: App): void => {
|
||||
app.component(BasicUpload.name, BasicUpload);
|
||||
};
|
||||
|
||||
withInstall(BasicUpload);
|
||||
export { BasicUpload };
|
||||
|
@ -1,8 +1,9 @@
|
||||
import BasicDragVerifyLib from './src/DragVerify';
|
||||
import RotateDragVerifyLib from './src/ImgRotate';
|
||||
import BasicDragVerify from './src/DragVerify';
|
||||
import RotateDragVerify from './src/ImgRotate';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
withInstall(BasicDragVerify, RotateDragVerify);
|
||||
|
||||
export * from './src/types';
|
||||
|
||||
export const RotateDragVerify = withInstall(RotateDragVerifyLib);
|
||||
export const BasicDragVerify = withInstall(BasicDragVerifyLib);
|
||||
export { BasicDragVerify, RotateDragVerify };
|
||||
|
@ -1,4 +1,5 @@
|
||||
import VirtualScrollLib from './src/index';
|
||||
import VirtualScroll from './src/index';
|
||||
import { withInstall } from '../util';
|
||||
|
||||
export const VirtualScroll = withInstall(VirtualScrollLib);
|
||||
withInstall(VirtualScroll);
|
||||
export { VirtualScroll };
|
||||
|
@ -1,12 +1,12 @@
|
||||
import type { VNodeChild, Plugin } from 'vue';
|
||||
import type { VNodeChild } from 'vue';
|
||||
import type { App } from 'vue';
|
||||
|
||||
export function withInstall<T>(component: T) {
|
||||
const comp = component as any;
|
||||
comp.install = (app: App) => {
|
||||
app.component(comp.displayName || comp.name, comp);
|
||||
};
|
||||
return comp as T & Plugin;
|
||||
export function withInstall(...components: any[]) {
|
||||
components.forEach((comp) => {
|
||||
comp.install = (app: App) => {
|
||||
app.component(comp.displayName || comp.name, comp);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function convertToUnit(
|
||||
|
@ -2,6 +2,8 @@
|
||||
@import 'easing';
|
||||
@import 'breakpoint';
|
||||
|
||||
@namespace: vben;
|
||||
|
||||
// tabs
|
||||
@multiple-height: 30px;
|
||||
|
||||
|
@ -1,21 +1,54 @@
|
||||
import { InjectionKey, provide, inject, reactive, readonly } from 'vue';
|
||||
import {
|
||||
InjectionKey,
|
||||
provide,
|
||||
inject,
|
||||
reactive,
|
||||
readonly as defineReadonly,
|
||||
defineComponent,
|
||||
UnwrapRef,
|
||||
} from 'vue';
|
||||
|
||||
export const createContext = <T>(
|
||||
context: any,
|
||||
contextInjectKey: InjectionKey<T> = Symbol(),
|
||||
_readonly = true
|
||||
) => {
|
||||
const state = reactive({ ...context });
|
||||
export interface CreateContextOptions {
|
||||
readonly?: boolean;
|
||||
createProvider?: boolean;
|
||||
}
|
||||
|
||||
const provideData = _readonly ? readonly(state) : state;
|
||||
provide(contextInjectKey, provideData);
|
||||
type ShallowUnwrap<T> = {
|
||||
[P in keyof T]: UnwrapRef<T[P]>;
|
||||
};
|
||||
|
||||
export function createContext<T>(
|
||||
context: any,
|
||||
key: InjectionKey<T> = Symbol(),
|
||||
options: CreateContextOptions = {}
|
||||
) {
|
||||
const { readonly = true, createProvider = false } = options;
|
||||
|
||||
const state = reactive(context);
|
||||
|
||||
const provideData = readonly ? defineReadonly(state) : state;
|
||||
!createProvider && provide(key, provideData);
|
||||
|
||||
const Provider = createProvider
|
||||
? defineComponent({
|
||||
name: 'Provider',
|
||||
inheritAttrs: false,
|
||||
setup(_, { slots }) {
|
||||
provide(key, provideData);
|
||||
return () => slots.default?.();
|
||||
},
|
||||
})
|
||||
: null;
|
||||
|
||||
return { Provider, state };
|
||||
}
|
||||
|
||||
export const useContext = <T>(
|
||||
contextInjectKey: InjectionKey<T> = Symbol(),
|
||||
key: InjectionKey<T> = Symbol(),
|
||||
defaultValue?: any,
|
||||
_readonly = true
|
||||
): T => {
|
||||
const state = inject(contextInjectKey, defaultValue || {});
|
||||
return _readonly ? readonly(state) : state;
|
||||
readonly = false
|
||||
): ShallowUnwrap<T> => {
|
||||
const state = inject(key, defaultValue || {});
|
||||
|
||||
return readonly ? defineReadonly(state) : state;
|
||||
};
|
||||
|
@ -39,8 +39,6 @@ export function useMenuSetting() {
|
||||
|
||||
const getCollapsedShowTitle = computed(() => unref(getMenuSetting).collapsedShowTitle);
|
||||
|
||||
const getCollapsedShowSearch = computed(() => unref(getMenuSetting).collapsedShowSearch);
|
||||
|
||||
const getTopMenuAlign = computed(() => unref(getMenuSetting).topMenuAlign);
|
||||
|
||||
const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR);
|
||||
@ -63,13 +61,6 @@ export function useMenuSetting() {
|
||||
return unref(getTrigger) === TriggerEnum.HEADER;
|
||||
});
|
||||
|
||||
const getShowSearch = computed(() => {
|
||||
return (
|
||||
unref(getMenuSetting).showSearch &&
|
||||
!(unref(getMenuType) === MenuTypeEnum.MIX && unref(getMenuMode) === MenuModeEnum.HORIZONTAL)
|
||||
);
|
||||
});
|
||||
|
||||
const getIsHorizontal = computed(() => {
|
||||
return unref(getMenuMode) === MenuModeEnum.HORIZONTAL;
|
||||
});
|
||||
@ -119,9 +110,7 @@ export function useMenuSetting() {
|
||||
getMenuTheme,
|
||||
getCanDrag,
|
||||
getIsHorizontal,
|
||||
getShowSearch,
|
||||
getCollapsedShowTitle,
|
||||
getCollapsedShowSearch,
|
||||
getIsSidebarType,
|
||||
getAccordion,
|
||||
getShowTopMenu,
|
||||
|
19
src/hooks/web/useDesign.ts
Normal file
19
src/hooks/web/useDesign.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { useAppProviderContext } from '/@/components/Application';
|
||||
import { computed } from 'vue';
|
||||
// import { useCssModule, reactive } from 'vue';
|
||||
export function useDesign(scope: string) {
|
||||
const values = useAppProviderContext();
|
||||
// const style = cssModule ? useCssModule() : {};
|
||||
|
||||
// if (cssModule) {
|
||||
// Object.keys(style).forEach((key) => {
|
||||
// const moduleCls = style[key];
|
||||
// style[key] = `${cls}-${moduleCls}`;
|
||||
// });
|
||||
// }
|
||||
return {
|
||||
prefixCls: computed(() => `${values.prefixCls}-${scope}`),
|
||||
prefixVar: values.prefixCls,
|
||||
// style,
|
||||
};
|
||||
}
|
@ -27,7 +27,6 @@ export function useLocale() {
|
||||
setLocalSetting({ lang });
|
||||
// i18n.global.setLocaleMessage(locale, messages);
|
||||
|
||||
antConfigLocaleRef.value = { a: 1 };
|
||||
switch (lang) {
|
||||
// Simplified Chinese
|
||||
case 'zh_CN':
|
||||
|
@ -188,7 +188,6 @@ export default defineComponent({
|
||||
theme={unref(getHeaderTheme)}
|
||||
splitType={unref(getSplitType)}
|
||||
menuMode={unref(getMenuMode)}
|
||||
showSearch={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
@ -27,9 +27,6 @@ export default defineComponent({
|
||||
default: MenuSplitTyeEnum.NONE,
|
||||
},
|
||||
|
||||
// Whether to show search box
|
||||
showSearch: propTypes.bool.def(true),
|
||||
|
||||
isHorizontal: propTypes.bool,
|
||||
// menu Mode
|
||||
menuMode: {
|
||||
@ -42,11 +39,9 @@ export default defineComponent({
|
||||
|
||||
const {
|
||||
setMenuSetting,
|
||||
getShowSearch,
|
||||
getMenuMode,
|
||||
getMenuType,
|
||||
getCollapsedShowTitle,
|
||||
getCollapsedShowSearch,
|
||||
getIsSidebarType,
|
||||
getMenuTheme,
|
||||
getCollapsed,
|
||||
@ -65,14 +60,6 @@ export default defineComponent({
|
||||
|
||||
const appendClass = computed(() => props.splitType === MenuSplitTyeEnum.TOP);
|
||||
|
||||
const showSearch = computed(() => {
|
||||
return (
|
||||
unref(getShowSearch) &&
|
||||
props.showSearch &&
|
||||
(unref(getCollapsedShowSearch) ? true : !unref(getCollapsed))
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* click menu
|
||||
* @param menu
|
||||
@ -122,7 +109,6 @@ export default defineComponent({
|
||||
collapsedShowTitle={unref(getCollapsedShowTitle)}
|
||||
theme={unref(getComputedMenuTheme)}
|
||||
showLogo={unref(showLogo)}
|
||||
search={unref(showSearch)}
|
||||
items={unref(menusRef)}
|
||||
flatItems={unref(flatMenusRef)}
|
||||
accordion={unref(getAccordion)}
|
||||
|
@ -21,7 +21,6 @@ export enum HandlerEnum {
|
||||
MENU_SHOW_SIDEBAR,
|
||||
MENU_THEME,
|
||||
MENU_SPLIT,
|
||||
MENU_SHOW_SEARCH,
|
||||
MENU_FIXED,
|
||||
|
||||
// header
|
||||
|
@ -63,9 +63,6 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf
|
||||
case HandlerEnum.MENU_FIXED:
|
||||
return { menuSetting: { fixed: value } };
|
||||
|
||||
case HandlerEnum.MENU_SHOW_SEARCH:
|
||||
return { menuSetting: { showSearch: value } };
|
||||
|
||||
// ============transition==================
|
||||
case HandlerEnum.OPEN_PAGE_LOADING:
|
||||
appStore.commitPageLoadingState(false);
|
||||
|
@ -15,7 +15,6 @@
|
||||
}
|
||||
|
||||
&:not(.ant-layout-sider-dark) {
|
||||
// border-right: 1px solid @border-color-light;
|
||||
box-shadow: 2px 0 8px 0 rgba(29, 35, 41, 0.05);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ export const getParentLayout = (name: string) => {
|
||||
export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
||||
path: '/:path(.*)*',
|
||||
name: 'ErrorPage',
|
||||
redirect: '/error/404',
|
||||
component: LAYOUT,
|
||||
meta: {
|
||||
title: 'ErrorPage',
|
||||
@ -33,7 +32,7 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '/error/404',
|
||||
path: '/:path(.*)*',
|
||||
name: 'ErrorPage',
|
||||
component: EXCEPTION_COMPONENT,
|
||||
meta: {
|
||||
|
@ -21,6 +21,9 @@ Object.keys(modules).forEach((key) => {
|
||||
// ===========================
|
||||
// ==========Helper===========
|
||||
// ===========================
|
||||
const isBackMode = () => {
|
||||
return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
|
||||
};
|
||||
|
||||
const staticMenus: Menu[] = [];
|
||||
(() => {
|
||||
@ -33,10 +36,6 @@ const staticMenus: Menu[] = [];
|
||||
}
|
||||
})();
|
||||
|
||||
const isBackMode = () => {
|
||||
return appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK;
|
||||
};
|
||||
|
||||
async function getAsyncMenus() {
|
||||
// 前端角色控制菜单 直接取菜单文件
|
||||
if (!isBackMode()) {
|
||||
|
@ -17,9 +17,11 @@ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
|
||||
export const SIDE_BAR_BG_COLOR_LIST: string[] = [
|
||||
'#273352',
|
||||
'#ffffff',
|
||||
'#191b24',
|
||||
'#191a23',
|
||||
'#001529',
|
||||
'#304156',
|
||||
'#001628',
|
||||
'#28333E',
|
||||
'#344058',
|
||||
];
|
||||
|
@ -89,8 +89,6 @@ const setting: ProjectConfig = {
|
||||
show: true,
|
||||
// Whether to show dom
|
||||
hidden: true,
|
||||
// Whether to show search box
|
||||
showSearch: true,
|
||||
// Menu width
|
||||
menuWidth: 210,
|
||||
// Menu mode
|
||||
|
1
src/types/config.d.ts
vendored
1
src/types/config.d.ts
vendored
@ -9,7 +9,6 @@ export interface MenuSetting {
|
||||
collapsed: boolean;
|
||||
collapsedShowTitle: boolean;
|
||||
canDrag: boolean;
|
||||
showSearch: boolean;
|
||||
show: boolean;
|
||||
hidden: boolean;
|
||||
split: boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user