feat: 布局问题

master
LCJ-MinYa 12 months ago
parent 1af036dfad
commit 5d0d614637

@ -0,0 +1,25 @@
<template>
<section class="base-container">
<slot></slot>
</section>
</template>
<script setup>
// import { computed } from 'vue';
// import { useGlobal } from '@pureadmin/utils';
// const { $storage } = useGlobal();
// const hideTabs = computed(() => {
// return $storage?.configure.hideTabs;
// });
</script>
<style lang="scss">
.base-container {
overflow: auto;
display: flex;
flex: 1;
flex-direction: column;
height: calc(100vh - 81px);
}
</style>

@ -0,0 +1,5 @@
<template>
<section class="base-container">
<slot></slot>
</section>
</template>

@ -0,0 +1,5 @@
<template>
<section class="base-container">
<slot></slot>
</section>
</template>

@ -0,0 +1,15 @@
<template>
<main class="base-main">
<slot></slot>
</main>
</template>
<style lang="scss">
.base-main {
display: flex;
flex-direction: column;
flex: 1;
overflow: auto;
height: calc(100vh - 81px);
}
</style>

@ -0,0 +1,14 @@
import { App, Component } from 'vue';
import BaseContainer from '@/components/AutoImport/BaseContainer/index.vue';
import BaseMain from '@/components/AutoImport/BaseMain/index.vue';
import BaseHeader from '@/components/AutoImport/BaseHeader/index.vue';
import BaseFooter from '@/components/AutoImport/BaseFooter/index.vue';
/** 注入全局组件 */
export function useAutoImport(app: App) {
// 全局注册组件
app.component('BaseContainer', BaseContainer);
app.component('BaseMain', BaseMain);
app.component('BaseHeader', BaseHeader);
app.component('BaseFooter', BaseFooter);
}

@ -1,213 +1,193 @@
<script setup lang="ts"> <script setup lang="ts">
import LayFrame from "../lay-frame/index.vue"; import LayFrame from '../lay-frame/index.vue';
import LayFooter from "../lay-footer/index.vue"; import LayFooter from '../lay-footer/index.vue';
import { useTags } from "@/layout/hooks/useTag"; import { useTags } from '@/layout/hooks/useTag';
import { useGlobal, isNumber } from "@pureadmin/utils"; import { useGlobal, isNumber } from '@pureadmin/utils';
import BackTopIcon from "@/assets/svg/back_top.svg?component"; import BackTopIcon from '@/assets/svg/back_top.svg?component';
import { h, computed, Transition, defineComponent } from "vue"; import { h, computed, Transition, defineComponent } from 'vue';
import { usePermissionStoreHook } from "@/store/modules/permission"; import { usePermissionStoreHook } from '@/store/modules/permission';
const props = defineProps({ const props = defineProps({
fixedHeader: Boolean fixedHeader: Boolean,
}); });
const { showModel } = useTags(); const { showModel } = useTags();
const { $storage, $config } = useGlobal<GlobalPropertiesApi>(); const { $storage, $config } = useGlobal<GlobalPropertiesApi>();
const isKeepAlive = computed(() => { const isKeepAlive = computed(() => {
return $config?.KeepAlive; return $config?.KeepAlive;
}); });
const transitions = computed(() => { const transitions = computed(() => {
return route => { return (route) => {
return route.meta.transition; return route.meta.transition;
}; };
}); });
const hideTabs = computed(() => { const hideTabs = computed(() => {
return $storage?.configure.hideTabs; return $storage?.configure.hideTabs;
}); });
const hideFooter = computed(() => { const hideFooter = computed(() => {
return $storage?.configure.hideFooter; return $storage?.configure.hideFooter;
}); });
const stretch = computed(() => { const stretch = computed(() => {
return $storage?.configure.stretch; return $storage?.configure.stretch;
}); });
const layout = computed(() => { const layout = computed(() => {
return $storage?.layout.layout === "vertical"; return $storage?.layout.layout === 'vertical';
}); });
const getMainWidth = computed(() => { const getMainWidth = computed(() => {
return isNumber(stretch.value) return isNumber(stretch.value) ? stretch.value + 'px' : stretch.value ? '1440px' : '100%';
? stretch.value + "px"
: stretch.value
? "1440px"
: "100%";
}); });
const getSectionStyle = computed(() => { const getSectionStyle = computed(() => {
return [ return [
hideTabs.value && layout ? "padding-top: 48px;" : "", hideTabs.value && layout ? 'padding-top: 48px;' : '',
!hideTabs.value && layout !hideTabs.value && layout ? (showModel.value == 'chrome' ? 'padding-top: 85px;' : 'padding-top: 81px;') : '',
? showModel.value == "chrome" hideTabs.value && !layout.value ? 'padding-top: 48px;' : '',
? "padding-top: 85px;" !hideTabs.value && !layout.value ? (showModel.value == 'chrome' ? 'padding-top: 85px;' : 'padding-top: 81px;') : '',
: "padding-top: 81px;" props.fixedHeader ? '' : `padding-top: 0;${hideTabs.value ? 'min-height: calc(100vh - 48px);' : 'min-height: calc(100vh - 86px);'}`,
: "", ];
hideTabs.value && !layout.value ? "padding-top: 48px;" : "",
!hideTabs.value && !layout.value
? showModel.value == "chrome"
? "padding-top: 85px;"
: "padding-top: 81px;"
: "",
props.fixedHeader
? ""
: `padding-top: 0;${
hideTabs.value
? "min-height: calc(100vh - 48px);"
: "min-height: calc(100vh - 86px);"
}`
];
}); });
const transitionMain = defineComponent({ const transitionMain = defineComponent({
props: { props: {
route: { route: {
type: undefined, type: undefined,
required: true required: true,
} },
}, },
render() { render() {
const transitionName = const transitionName = transitions.value(this.route)?.name || 'fade-transform';
transitions.value(this.route)?.name || "fade-transform"; const enterTransition = transitions.value(this.route)?.enterTransition;
const enterTransition = transitions.value(this.route)?.enterTransition; const leaveTransition = transitions.value(this.route)?.leaveTransition;
const leaveTransition = transitions.value(this.route)?.leaveTransition; return h(
return h( Transition,
Transition, {
{ name: enterTransition ? 'pure-classes-transition' : transitionName,
name: enterTransition ? "pure-classes-transition" : transitionName, enterActiveClass: enterTransition ? `animate__animated ${enterTransition}` : undefined,
enterActiveClass: enterTransition leaveActiveClass: leaveTransition ? `animate__animated ${leaveTransition}` : undefined,
? `animate__animated ${enterTransition}` mode: 'out-in',
: undefined, appear: true,
leaveActiveClass: leaveTransition },
? `animate__animated ${leaveTransition}` {
: undefined, default: () => [this.$slots.default()],
mode: "out-in", }
appear: true );
}, },
{
default: () => [this.$slots.default()]
}
);
}
}); });
</script> </script>
<template> <template>
<section <section
:class="[fixedHeader ? 'app-main' : 'app-main-nofixed-header']" :class="[fixedHeader ? 'app-main' : 'app-main-nofixed-header']"
:style="getSectionStyle" :style="getSectionStyle"
> >
<router-view> <router-view>
<template #default="{ Component, route }"> <template #default="{ Component, route }">
<LayFrame :currComp="Component" :currRoute="route"> <LayFrame
<template #default="{ Comp, fullPath, frameInfo }"> :currComp="Component"
<el-scrollbar :currRoute="route"
v-if="fixedHeader"
:wrap-style="{
display: 'flex',
'flex-wrap': 'wrap',
'max-width': getMainWidth,
margin: '0 auto',
transition: 'all 300ms cubic-bezier(0.4, 0, 0.2, 1)'
}"
:view-style="{
display: 'flex',
flex: 'auto',
overflow: 'hidden',
'flex-direction': 'column'
}"
>
<el-backtop
title="回到顶部"
target=".app-main .el-scrollbar__wrap"
>
<BackTopIcon />
</el-backtop>
<div class="grow">
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component
:is="Comp"
:key="fullPath"
:frameInfo="frameInfo"
class="main-content"
/>
</keep-alive>
<component
:is="Comp"
v-else
:key="fullPath"
:frameInfo="frameInfo"
class="main-content"
/>
</transitionMain>
</div>
<LayFooter v-if="!hideFooter" />
</el-scrollbar>
<div v-else class="grow">
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
:include="usePermissionStoreHook().cachePageList"
> >
<component <template #default="{ Comp, fullPath, frameInfo }">
:is="Comp" <el-scrollbar
:key="fullPath" v-if="fixedHeader"
:frameInfo="frameInfo" :wrap-style="{
class="main-content" display: 'flex',
/> 'flex-wrap': 'wrap',
</keep-alive> 'max-width': getMainWidth,
<component margin: '0 auto',
:is="Comp" transition: 'all 300ms cubic-bezier(0.4, 0, 0.2, 1)',
v-else }"
:key="fullPath" :view-style="{
:frameInfo="frameInfo" display: 'flex',
class="main-content" flex: 'auto',
/> overflow: 'hidden',
</transitionMain> 'flex-direction': 'column',
</div> }"
</template> >
</LayFrame> <el-backtop
</template> title="回到顶部"
</router-view> target=".app-main .el-scrollbar__wrap"
>
<!-- 页脚 --> <BackTopIcon />
<LayFooter v-if="!hideFooter && !fixedHeader" /> </el-backtop>
</section>
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component
:is="Comp"
:key="fullPath"
:frameInfo="frameInfo"
class="main-content"
/>
</keep-alive>
<component
:is="Comp"
v-else
:key="fullPath"
:frameInfo="frameInfo"
class="main-content"
/>
</transitionMain>
<LayFooter v-if="!hideFooter" />
</el-scrollbar>
<template v-else>
<transitionMain :route="route">
<keep-alive
v-if="isKeepAlive"
:include="usePermissionStoreHook().cachePageList"
>
<component
:is="Comp"
:key="fullPath"
:frameInfo="frameInfo"
class="main-content"
/>
</keep-alive>
<component
:is="Comp"
v-else
:key="fullPath"
:frameInfo="frameInfo"
class="main-content"
/>
</transitionMain>
</template>
</template>
</LayFrame>
</template>
</router-view>
<!-- 页脚 -->
<LayFooter v-if="!hideFooter && !fixedHeader" />
</section>
</template> </template>
<style scoped> <style scoped>
.app-main { .app-main {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100vh; height: 100vh;
overflow-x: hidden; overflow-x: hidden;
} }
.app-main-nofixed-header { .app-main-nofixed-header {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
} }
.main-content { .main-content {
margin: 24px; margin: 0;
} }
</style> </style>

@ -1,64 +1,61 @@
import App from "./App.vue"; import App from './App.vue';
import router from "./router"; import router from './router';
import { setupStore } from "@/store"; import { setupStore } from '@/store';
import { getPlatformConfig } from "./config"; import { getPlatformConfig } from './config';
import { MotionPlugin } from "@vueuse/motion"; import { MotionPlugin } from '@vueuse/motion';
// import { useEcharts } from "@/plugins/echarts"; // import { useEcharts } from "@/plugins/echarts";
import { createApp, type Directive } from "vue"; import { createApp, type Directive } from 'vue';
import { useElementPlus } from "@/plugins/elementPlus"; import { useElementPlus } from '@/plugins/elementPlus';
import { injectResponsiveStorage } from "@/utils/responsive"; import { injectResponsiveStorage } from '@/utils/responsive';
import { useAutoImport } from '@/components/AutoImport';
import Table from "@pureadmin/table"; import Table from '@pureadmin/table';
// import PureDescriptions from "@pureadmin/descriptions"; // import PureDescriptions from "@pureadmin/descriptions";
// 引入重置样式 // 引入重置样式
import "./style/reset.scss"; import './style/reset.scss';
// 导入公共样式 // 导入公共样式
import "./style/index.scss"; import './style/index.scss';
// 一定要在main.ts中导入tailwind.css防止vite每次hmr都会请求src/style/index.scss整体css文件导致热更新慢的问题 // 一定要在main.ts中导入tailwind.css防止vite每次hmr都会请求src/style/index.scss整体css文件导致热更新慢的问题
import "./style/tailwind.css"; import './style/tailwind.css';
import "element-plus/dist/index.css"; import 'element-plus/dist/index.css';
// 导入字体图标 // 导入字体图标
import "./assets/iconfont/iconfont.js"; import './assets/iconfont/iconfont.js';
import "./assets/iconfont/iconfont.css"; import './assets/iconfont/iconfont.css';
const app = createApp(App); const app = createApp(App);
// 自定义指令 // 自定义指令
import * as directives from "@/directives"; import * as directives from '@/directives';
Object.keys(directives).forEach(key => { Object.keys(directives).forEach((key) => {
app.directive(key, (directives as { [key: string]: Directive })[key]); app.directive(key, (directives as { [key: string]: Directive })[key]);
}); });
// 全局注册@iconify/vue图标库 // 全局注册@iconify/vue图标库
import { import { IconifyIconOffline, IconifyIconOnline, FontIcon } from './components/ReIcon';
IconifyIconOffline, app.component('IconifyIconOffline', IconifyIconOffline);
IconifyIconOnline, app.component('IconifyIconOnline', IconifyIconOnline);
FontIcon app.component('FontIcon', FontIcon);
} from "./components/ReIcon";
app.component("IconifyIconOffline", IconifyIconOffline);
app.component("IconifyIconOnline", IconifyIconOnline);
app.component("FontIcon", FontIcon);
// 全局注册按钮级别权限组件 // 全局注册按钮级别权限组件
import { Auth } from "@/components/ReAuth"; import { Auth } from '@/components/ReAuth';
import { Perms } from "@/components/RePerms"; import { Perms } from '@/components/RePerms';
app.component("Auth", Auth); app.component('Auth', Auth);
app.component("Perms", Perms); app.component('Perms', Perms);
// 全局注册vue-tippy // 全局注册vue-tippy
import "tippy.js/dist/tippy.css"; import 'tippy.js/dist/tippy.css';
import "tippy.js/themes/light.css"; import 'tippy.js/themes/light.css';
import VueTippy from "vue-tippy"; import VueTippy from 'vue-tippy';
app.use(VueTippy); app.use(VueTippy);
getPlatformConfig(app).then(async config => { getPlatformConfig(app).then(async (config) => {
setupStore(app); setupStore(app);
app.use(router); app.use(router);
await router.isReady(); await router.isReady();
injectResponsiveStorage(app, config); injectResponsiveStorage(app, config);
app.use(MotionPlugin).use(useElementPlus).use(Table); app.use(MotionPlugin).use(useElementPlus).use(useAutoImport).use(Table);
// .use(PureDescriptions) // .use(PureDescriptions)
// .use(useEcharts); // .use(useEcharts);
app.mount("#app"); app.mount('#app');
}); });

@ -1,248 +1,245 @@
// 按需引入element-plus该方法稳定且明确。当然也支持https://element-plus.org/zh-CN/guide/quickstart.html#%E6%8C%89%E9%9C%80%E5%AF%BC%E5%85%A5 // 按需引入element-plus该方法稳定且明确。当然也支持https://element-plus.org/zh-CN/guide/quickstart.html#%E6%8C%89%E9%9C%80%E5%AF%BC%E5%85%A5
import type { App, Component } from "vue"; import type { App, Component } from 'vue';
import { import {
/** /**
* 便 element-plus 使 * 便 element-plus 使
* https://github.com/element-plus/element-plus/blob/dev/packages/element-plus/component.ts#L111-L211 * https://github.com/element-plus/element-plus/blob/dev/packages/element-plus/component.ts#L111-L211
* */ * */
ElAffix, ElAffix,
ElAlert, ElAlert,
ElAutocomplete, ElAutocomplete,
ElAutoResizer, ElAutoResizer,
ElAvatar, ElAvatar,
ElAnchor, ElAnchor,
ElAnchorLink, ElAnchorLink,
ElBacktop, ElBacktop,
ElBadge, ElBadge,
ElBreadcrumb, ElBreadcrumb,
ElBreadcrumbItem, ElBreadcrumbItem,
ElButton, ElButton,
ElButtonGroup, ElButtonGroup,
ElCalendar, ElCalendar,
ElCard, ElCard,
ElCarousel, ElCarousel,
ElCarouselItem, ElCarouselItem,
ElCascader, ElCascader,
ElCascaderPanel, ElCascaderPanel,
ElCheckTag, ElCheckTag,
ElCheckbox, ElCheckbox,
ElCheckboxButton, ElCheckboxButton,
ElCheckboxGroup, ElCheckboxGroup,
ElCol, ElCol,
ElCollapse, ElCollapse,
ElCollapseItem, ElCollapseItem,
ElCollapseTransition, ElCollapseTransition,
ElColorPicker, ElColorPicker,
ElConfigProvider, ElConfigProvider,
ElContainer, ElContainer,
ElAside, ElAside,
ElFooter, ElFooter,
ElHeader, ElHeader,
ElMain, ElMain,
ElDatePicker, ElDatePicker,
ElDescriptions, ElDescriptions,
ElDescriptionsItem, ElDescriptionsItem,
ElDialog, ElDialog,
ElDivider, ElDivider,
ElDrawer, ElDrawer,
ElDropdown, ElDropdown,
ElDropdownItem, ElDropdownItem,
ElDropdownMenu, ElDropdownMenu,
ElEmpty, ElEmpty,
ElForm, ElForm,
ElFormItem, ElFormItem,
ElIcon, ElIcon,
ElImage, ElImage,
ElImageViewer, ElImageViewer,
ElInput, ElInput,
ElInputNumber, ElInputNumber,
ElLink, ElLink,
ElMenu, ElMenu,
ElMenuItem, ElMenuItem,
ElMenuItemGroup, ElMenuItemGroup,
ElSubMenu, ElSubMenu,
ElPageHeader, ElPageHeader,
ElPagination, ElPagination,
ElPopconfirm, ElPopconfirm,
ElPopover, ElPopover,
ElPopper, ElPopper,
ElProgress, ElProgress,
ElRadio, ElRadio,
ElRadioButton, ElRadioButton,
ElRadioGroup, ElRadioGroup,
ElRate, ElRate,
ElResult, ElResult,
ElRow, ElRow,
ElScrollbar, ElScrollbar,
ElSelect, ElSelect,
ElOption, ElOption,
ElOptionGroup, ElOptionGroup,
ElSelectV2, ElSelectV2,
ElSkeleton, ElSkeleton,
ElSkeletonItem, ElSkeletonItem,
ElSlider, ElSlider,
ElSpace, ElSpace,
ElStatistic, ElStatistic,
ElCountdown, ElCountdown,
ElSteps, ElSteps,
ElStep, ElStep,
ElSwitch, ElSwitch,
ElTable, ElTable,
ElTableColumn, ElTableColumn,
ElTableV2, ElTableV2,
ElTabs, ElTabs,
ElTabPane, ElTabPane,
ElTag, ElTag,
ElText, ElText,
ElTimePicker, ElTimePicker,
ElTimeSelect, ElTimeSelect,
ElTimeline, ElTimeline,
ElTimelineItem, ElTimelineItem,
ElTooltip, ElTooltip,
ElTransfer, ElTransfer,
ElTree, ElTree,
ElTreeSelect, ElTreeSelect,
ElTreeV2, ElTreeV2,
ElUpload, ElUpload,
ElWatermark, ElWatermark,
ElTour, ElTour,
ElTourStep, ElTourStep,
ElSegmented, ElSegmented,
/** /**
* 便 element-plus 使 * 便 element-plus 使
* https://github.com/element-plus/element-plus/blob/dev/packages/element-plus/plugin.ts#L11-L16 * https://github.com/element-plus/element-plus/blob/dev/packages/element-plus/plugin.ts#L11-L16
* */ * */
ElLoading, // v-loading 指令 ElLoading, // v-loading 指令
ElInfiniteScroll, // v-infinite-scroll 指令 ElInfiniteScroll, // v-infinite-scroll 指令
ElPopoverDirective, // v-popover 指令 ElPopoverDirective, // v-popover 指令
ElMessage, // $message 全局属性对象globalProperties ElMessage, // $message 全局属性对象globalProperties
ElMessageBox, // $msgbox、$alert、$confirm、$prompt 全局属性对象globalProperties ElMessageBox, // $msgbox、$alert、$confirm、$prompt 全局属性对象globalProperties
ElNotification // $notify 全局属性对象globalProperties ElNotification, // $notify 全局属性对象globalProperties
} from "element-plus"; } from 'element-plus';
const components = [ const components = [
ElAffix, ElAffix,
ElAlert, ElAlert,
ElAutocomplete, ElAutocomplete,
ElAutoResizer, ElAutoResizer,
ElAvatar, ElAvatar,
ElAnchor, ElAnchor,
ElAnchorLink, ElAnchorLink,
ElBacktop, ElBacktop,
ElBadge, ElBadge,
ElBreadcrumb, ElBreadcrumb,
ElBreadcrumbItem, ElBreadcrumbItem,
ElButton, ElButton,
ElButtonGroup, ElButtonGroup,
ElCalendar, ElCalendar,
ElCard, ElCard,
ElCarousel, ElCarousel,
ElCarouselItem, ElCarouselItem,
ElCascader, ElCascader,
ElCascaderPanel, ElCascaderPanel,
ElCheckTag, ElCheckTag,
ElCheckbox, ElCheckbox,
ElCheckboxButton, ElCheckboxButton,
ElCheckboxGroup, ElCheckboxGroup,
ElCol, ElCol,
ElCollapse, ElCollapse,
ElCollapseItem, ElCollapseItem,
ElCollapseTransition, ElCollapseTransition,
ElColorPicker, ElColorPicker,
ElConfigProvider, ElConfigProvider,
ElContainer, ElContainer,
ElAside, ElAside,
ElFooter, ElFooter,
ElHeader, ElHeader,
ElMain, ElMain,
ElDatePicker, ElDatePicker,
ElDescriptions, ElDescriptions,
ElDescriptionsItem, ElDescriptionsItem,
ElDialog, ElDialog,
ElDivider, ElDivider,
ElDrawer, ElDrawer,
ElDropdown, ElDropdown,
ElDropdownItem, ElDropdownItem,
ElDropdownMenu, ElDropdownMenu,
ElEmpty, ElEmpty,
ElForm, ElForm,
ElFormItem, ElFormItem,
ElIcon, ElIcon,
ElImage, ElImage,
ElImageViewer, ElImageViewer,
ElInput, ElInput,
ElInputNumber, ElInputNumber,
ElLink, ElLink,
ElMenu, ElMenu,
ElMenuItem, ElMenuItem,
ElMenuItemGroup, ElMenuItemGroup,
ElSubMenu, ElSubMenu,
ElPageHeader, ElPageHeader,
ElPagination, ElPagination,
ElPopconfirm, ElPopconfirm,
ElPopover, ElPopover,
ElPopper, ElPopper,
ElProgress, ElProgress,
ElRadio, ElRadio,
ElRadioButton, ElRadioButton,
ElRadioGroup, ElRadioGroup,
ElRate, ElRate,
ElResult, ElResult,
ElRow, ElRow,
ElScrollbar, ElScrollbar,
ElSelect, ElSelect,
ElOption, ElOption,
ElOptionGroup, ElOptionGroup,
ElSelectV2, ElSelectV2,
ElSkeleton, ElSkeleton,
ElSkeletonItem, ElSkeletonItem,
ElSlider, ElSlider,
ElSpace, ElSpace,
ElStatistic, ElStatistic,
ElCountdown, ElCountdown,
ElSteps, ElSteps,
ElStep, ElStep,
ElSwitch, ElSwitch,
ElTable, ElTable,
ElTableColumn, ElTableColumn,
ElTableV2, ElTableV2,
ElTabs, ElTabs,
ElTabPane, ElTabPane,
ElTag, ElTag,
ElText, ElText,
ElTimePicker, ElTimePicker,
ElTimeSelect, ElTimeSelect,
ElTimeline, ElTimeline,
ElTimelineItem, ElTimelineItem,
ElTooltip, ElTooltip,
ElTransfer, ElTransfer,
ElTree, ElTree,
ElTreeSelect, ElTreeSelect,
ElTreeV2, ElTreeV2,
ElUpload, ElUpload,
ElWatermark, ElWatermark,
ElTour, ElTour,
ElTourStep, ElTourStep,
ElSegmented ElSegmented,
]; ];
const plugins = [ const plugins = [ElLoading, ElInfiniteScroll, ElPopoverDirective, ElMessage, ElMessageBox, ElNotification];
ElLoading,
ElInfiniteScroll, /** 设置部分组件的默认属性 */
ElPopoverDirective, ElCard.props.shadow = { type: String, default: 'never' };
ElMessage, ElButton.props.round = { type: Boolean, default: true };
ElMessageBox,
ElNotification
];
/** 按需引入`element-plus` */ /** 按需引入`element-plus` */
export function useElementPlus(app: App) { export function useElementPlus(app: App) {
// 全局注册组件 // 全局注册组件
components.forEach((component: Component) => { components.forEach((component: Component) => {
app.component(component.name, component); app.component(component.name, component);
}); });
// 全局注册插件 // 全局注册插件
plugins.forEach(plugin => { plugins.forEach((plugin) => {
app.use(plugin); app.use(plugin);
}); });
} }

@ -19,5 +19,13 @@ export default {
title: '基础模版', title: '基础模版',
}, },
}, },
{
path: '/template/layout',
name: 'TemplateLayout',
component: () => import('@/views/template/layout/index.vue'),
meta: {
title: '布局模版',
},
},
], ],
} satisfies RouteConfigsTable; } satisfies RouteConfigsTable;

@ -1,188 +1,193 @@
.el-form-item__label { .el-form-item__label {
font-weight: 700; font-weight: 700;
} }
.el-breadcrumb__inner, .el-breadcrumb__inner,
.el-breadcrumb__inner a { .el-breadcrumb__inner a {
font-weight: 400 !important; font-weight: 400 !important;
} }
.el-dropdown-menu { .el-dropdown-menu {
padding: 0 !important; padding: 0 !important;
} }
.is-dark { .is-dark {
z-index: 9999 !important; z-index: 9999 !important;
} }
/* 重置 el-button 中 icon 的 margin */ /* 重置 el-button 中 icon 的 margin */
.reset-margin [class*="el-icon"] + span { .reset-margin [class*='el-icon'] + span {
margin-left: 2px !important; margin-left: 2px !important;
} }
/* 自定义 popover 的类名 */ /* 自定义 popover 的类名 */
.pure-popper { .pure-popper {
padding: 0 !important; padding: 0 !important;
} }
/* nprogress 适配 element-plus 的主题色 */ /* nprogress 适配 element-plus 的主题色 */
#nprogress { #nprogress {
& .bar { & .bar {
background-color: var(--el-color-primary) !important; background-color: var(--el-color-primary) !important;
} }
& .peg { & .peg {
box-shadow: box-shadow:
0 0 10px var(--el-color-primary), 0 0 10px var(--el-color-primary),
0 0 5px var(--el-color-primary) !important; 0 0 5px var(--el-color-primary) !important;
} }
& .spinner-icon { & .spinner-icon {
border-top-color: var(--el-color-primary); border-top-color: var(--el-color-primary);
border-left-color: var(--el-color-primary); border-left-color: var(--el-color-primary);
} }
} }
.pure-dialog { .pure-dialog {
.el-dialog__header.show-close { .el-dialog__header.show-close {
padding-right: 16px; padding-right: 16px;
} }
.el-dialog__headerbtn { .el-dialog__headerbtn {
top: 16px; top: 16px;
right: 12px; right: 12px;
width: 24px; width: 24px;
height: 24px; height: 24px;
} }
.pure-dialog-svg { .pure-dialog-svg {
color: var(--el-color-info); color: var(--el-color-info);
} }
.el-dialog__footer { .el-dialog__footer {
padding-top: 0; padding-top: 0;
} }
} }
/* 全局覆盖element-plus的el-tour、el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标和el-upload上传文件列表右侧关闭图标的样式表现更鲜明 */ /* 全局覆盖element-plus的el-tour、el-dialog、el-drawer、el-message-box、el-notification组件右上角关闭图标和el-upload上传文件列表右侧关闭图标的样式表现更鲜明 */
.el-dialog__headerbtn, .el-dialog__headerbtn,
.el-message-box__headerbtn { .el-message-box__headerbtn {
&:hover { &:hover {
.el-dialog__close { .el-dialog__close {
color: var(--el-color-info) !important; color: var(--el-color-info) !important;
}
} }
}
} }
.el-icon { .el-icon {
&.el-tour__close, &.el-tour__close,
&.el-dialog__close, &.el-dialog__close,
&.el-drawer__close, &.el-drawer__close,
&.el-message-box__close, &.el-message-box__close,
&.el-notification__closeBtn, &.el-notification__closeBtn,
.el-upload-list__item.is-ready &.el-icon--close { .el-upload-list__item.is-ready &.el-icon--close {
width: 24px; width: 24px;
height: 24px; height: 24px;
border-radius: 4px; border-radius: 4px;
outline: none; outline: none;
transition: transition:
background-color 0.2s, background-color 0.2s,
color 0.2s; color 0.2s;
&:hover { &:hover {
color: rgb(0 0 0 / 88%) !important; color: rgb(0 0 0 / 88%) !important;
text-decoration: none; text-decoration: none;
background-color: rgb(0 0 0 / 6%); background-color: rgb(0 0 0 / 6%);
.pure-dialog-svg { .pure-dialog-svg {
color: rgb(0 0 0 / 88%) !important; color: rgb(0 0 0 / 88%) !important;
} }
}
} }
}
} }
/* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,整体暗色风格在 src/style/dark.scss 文件进行了适配 */ /* 克隆并自定义 ElMessage 样式,不会影响 ElMessage 原本样式,在 src/utils/message.ts 中调用自定义样式 ElMessage 方法即可,整体暗色风格在 src/style/dark.scss 文件进行了适配 */
.pure-message { .pure-message {
background: #fff !important; background: #fff !important;
border-width: 0 !important; border-width: 0 !important;
box-shadow: box-shadow:
0 3px 6px -4px #0000001f, 0 3px 6px -4px #0000001f,
0 6px 16px #00000014, 0 6px 16px #00000014,
0 9px 28px 8px #0000000d !important; 0 9px 28px 8px #0000000d !important;
& .el-message__content { & .el-message__content {
color: #000000d9 !important; color: #000000d9 !important;
pointer-events: all !important; pointer-events: all !important;
background-image: initial !important; background-image: initial !important;
} }
& .el-message__closeBtn {
border-radius: 4px;
outline: none;
transition:
background-color 0.2s,
color 0.2s;
&:hover { & .el-message__closeBtn {
background-color: rgb(0 0 0 / 6%); border-radius: 4px;
outline: none;
transition:
background-color 0.2s,
color 0.2s;
&:hover {
background-color: rgb(0 0 0 / 6%);
}
} }
}
} }
/* 自定义菜单搜索样式 */ /* 自定义菜单搜索样式 */
.pure-search-dialog { .pure-search-dialog {
@media screen and (width > 760px) and (width <= 940px) { @media screen and (width > 760px) and (width <= 940px) {
.el-input__inner { .el-input__inner {
font-size: 12px; font-size: 12px;
}
} }
}
@media screen and (width <= 470px) { @media screen and (width <= 470px) {
.el-input__inner { .el-input__inner {
font-size: 12px; font-size: 12px;
}
} }
}
.el-dialog__header { .el-dialog__header {
display: none; display: none;
} }
.el-input__inner { .el-input__inner {
font-size: 1.2em; font-size: 1.2em;
} }
.el-dialog__footer { .el-dialog__footer {
width: calc(100% + 32px); width: calc(100% + 32px);
padding: 10px 20px; padding: 10px 20px;
margin: auto -16px -16px; margin: auto -16px -16px;
box-shadow: box-shadow:
0 -1px 0 0 #e0e3e8, 0 -1px 0 0 #e0e3e8,
0 -3px 6px 0 rgb(69 98 155 / 12%); 0 -3px 6px 0 rgb(69 98 155 / 12%);
} }
} }
/* 仿 el-scrollbar 滚动条样式支持大多数浏览器如Chrome、Edge、Firefox、Safari等。整体暗色风格在 src/style/dark.scss 文件进行了适配 */ /* 仿 el-scrollbar 滚动条样式支持大多数浏览器如Chrome、Edge、Firefox、Safari等。整体暗色风格在 src/style/dark.scss 文件进行了适配 */
.pure-scrollbar { .pure-scrollbar {
/* Firefox */ /* Firefox */
scrollbar-width: thin; /* 可选值为 'auto', 'thin', 'none' */ scrollbar-width: thin; /* 可选值为 'auto', 'thin', 'none' */
scrollbar-color: rgb(221 222 224) transparent; /* 滑块颜色、轨道颜色 */ scrollbar-color: rgb(221 222 224) transparent; /* 滑块颜色、轨道颜色 */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 6px; /* 滚动条宽度 */ width: 6px; /* 滚动条宽度 */
} }
/* 滚动条轨道 */ /* 滚动条轨道 */
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
background: transparent; /* 轨道颜色 */ background: transparent; /* 轨道颜色 */
} }
/* 滚动条滑块 */ /* 滚动条滑块 */
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
background-color: rgb(221 222 224); background-color: rgb(221 222 224);
border-radius: 4px; border-radius: 4px;
} }
/* 滚动条滑块hover状态 */ /* 滚动条滑块hover状态 */
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
background: rgb(199 201 203); /* 滑块hover颜色 */ background: rgb(199 201 203); /* 滑块hover颜色 */
} }
}
/** 默认el-card没有边框 */
.el-card {
border: none !important;
} }

@ -0,0 +1,225 @@
<template>
<Base-Container>
<pure-table
class="base-main"
:data="tableData"
:columns="columns"
size="large"
/>
</Base-Container>
</template>
<script setup lang="jsx">
import { ref } from 'vue';
defineOptions({
name: 'TemplateLayout',
});
const tableData = ref([
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
{
name: 'John',
age: 25,
},
{
name: 'Jane',
age: 30,
},
{
name: 'Bob',
age: 28,
},
]);
const columns = [
{
label: '姓名',
prop: 'name',
},
{
label: '年龄',
prop: 'age',
},
];
</script>
<style lang="scss" scoped></style>
Loading…
Cancel
Save