mirror of
https://github.com/pure-admin/vue-pure-admin.git
synced 2025-11-09 13:53:38 +08:00
chore:更换到主分支
This commit is contained in:
46
src/layout/components/AppMain.vue
Normal file
46
src/layout/components/AppMain.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<section class="app-main">
|
||||
<router-view :key="key" v-slot="{ Component }">
|
||||
<transition appear name="fade-transform" mode="out-in">
|
||||
<keep-alive>
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
</router-view>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, defineComponent } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
export default defineComponent({
|
||||
name: "AppMain",
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const key = computed(() => route.path);
|
||||
|
||||
return { key };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-main {
|
||||
min-height: calc(100vh - 50px);
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow-x: hidden;
|
||||
margin: 10px;
|
||||
}
|
||||
.fixed-header + .app-main {
|
||||
padding-top: 50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
.el-popup-parent--hidden {
|
||||
.fixed-header {
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
178
src/layout/components/Navbar.vue
Normal file
178
src/layout/components/Navbar.vue
Normal file
@@ -0,0 +1,178 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger
|
||||
:is-active="sidebar.opened"
|
||||
class="hamburger-container"
|
||||
@toggleClick="toggleSideBar"
|
||||
/>
|
||||
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
|
||||
<div class="right-menu">
|
||||
<screenfull />
|
||||
<div class="inter" :title="langs ? '中文' : '英文'" @click="toggleLang">
|
||||
<img :src="langs ? ch : en" />
|
||||
</div>
|
||||
<el-dropdown>
|
||||
<span class="el-dropdown-link">
|
||||
<img :src="favicon" />
|
||||
<p>{{ usename }}</p>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item icon="el-icon-switch-button" @click="logout">
|
||||
{{ $t("LoginOut") }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref, reactive, defineComponent, onMounted, nextTick } from "vue";
|
||||
import Breadcrumb from "../../components/breadCrumb/index.vue";
|
||||
import Hamburger from "../../components/hamBurger/index.vue";
|
||||
import screenfull from "../components/screenfull/index.vue";
|
||||
import { useMapGetters } from "../store";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { mapGetters, useStore } from "vuex";
|
||||
import { storageSession } from "../../utils/storage";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import ch from "/@/assets/ch.png";
|
||||
import en from "/@/assets/en.png";
|
||||
import favicon from "/favicon.ico";
|
||||
export default defineComponent({
|
||||
name: "Navbar",
|
||||
components: {
|
||||
Breadcrumb,
|
||||
Hamburger,
|
||||
screenfull,
|
||||
},
|
||||
setup() {
|
||||
let langs = ref(true);
|
||||
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
|
||||
let usename = storageSession.getItem("info").username;
|
||||
|
||||
const { locale } = useI18n();
|
||||
|
||||
// 国际化语言切换
|
||||
const toggleLang = (): void => {
|
||||
langs.value = !langs.value;
|
||||
langs.value ? (locale.value = "ch") : (locale.value = "en");
|
||||
};
|
||||
|
||||
// 退出登录
|
||||
const logout = (): void => {
|
||||
storageSession.removeItem("info");
|
||||
router.push("/login");
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
document
|
||||
.querySelector(".el-dropdown__popper")
|
||||
?.setAttribute("class", "resetTop");
|
||||
document
|
||||
.querySelector(".el-popper__arrow")
|
||||
?.setAttribute("class", "hidden");
|
||||
});
|
||||
|
||||
return {
|
||||
// @ts-ignore
|
||||
...useMapGetters(["sidebar"]),
|
||||
toggleSideBar() {
|
||||
store.dispatch("app/toggleSideBar");
|
||||
},
|
||||
langs,
|
||||
usename,
|
||||
toggleLang,
|
||||
logout,
|
||||
ch,
|
||||
en,
|
||||
favicon
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.navbar {
|
||||
height: 50px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
|
||||
.hamburger-container {
|
||||
line-height: 46px;
|
||||
height: 100%;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.3s;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.025);
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.right-menu {
|
||||
float: right;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.inter {
|
||||
width: 40px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
margin-right: 5px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
img {
|
||||
width: 25px;
|
||||
}
|
||||
}
|
||||
.el-dropdown-link {
|
||||
width: 80px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
margin-right: 20px;
|
||||
p {
|
||||
font-size: 13px;
|
||||
}
|
||||
&:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
img {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// single element-plus reset
|
||||
.el-dropdown-menu__item {
|
||||
padding: 0 10px;
|
||||
}
|
||||
.el-dropdown-menu {
|
||||
padding: 0;
|
||||
}
|
||||
.el-dropdown-menu__item:focus,
|
||||
.el-dropdown-menu__item:not(.is-disabled):hover {
|
||||
color: #606266;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
4
src/layout/components/index.ts
Normal file
4
src/layout/components/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export { default as Navbar } from './Navbar.vue'
|
||||
export { default as Sidebar } from './sidebar/index.vue'
|
||||
export { default as AppMain } from './AppMain.vue'
|
||||
export { default as setting } from './setting/index.vue'
|
||||
133
src/layout/components/panel/index.vue
Normal file
133
src/layout/components/panel/index.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div ref="right-panel" :class="{ show: show }" class="right-panel-container">
|
||||
<div class="right-panel-background" />
|
||||
<div class="right-panel">
|
||||
<div
|
||||
class="handle-button"
|
||||
:title="show ? '关闭设置' : '打开设置'"
|
||||
@click="show = !show"
|
||||
>
|
||||
<i :class="show ? 'el-icon-close' : 'el-icon-setting'" />
|
||||
</div>
|
||||
<div class="right-panel-items">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { addClass, removeClass } from "../../../utils/operate";
|
||||
import { ref, watch, getCurrentInstance, onMounted, onBeforeMount } from "vue";
|
||||
export default {
|
||||
name: "panel",
|
||||
setup() {
|
||||
let vm: any;
|
||||
|
||||
let show = ref(false);
|
||||
|
||||
watch(
|
||||
show,
|
||||
(val, prevVal) => {
|
||||
val ? addEventClick() : () => {};
|
||||
if (val) {
|
||||
addClass(document.body, "showright-panel");
|
||||
} else {
|
||||
removeClass(document.body, "showright-panel");
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const addEventClick = (): void => {
|
||||
window.addEventListener("click", closeSidebar);
|
||||
};
|
||||
|
||||
const closeSidebar = (evt: any): void => {
|
||||
const parent = evt.target.closest(".right-panel");
|
||||
if (!parent) {
|
||||
show.value = false;
|
||||
window.removeEventListener("click", closeSidebar);
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
vm = getCurrentInstance();
|
||||
});
|
||||
|
||||
return {
|
||||
show,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.showright-panel {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: calc(100% - 15px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.right-panel-background {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
width: 100%;
|
||||
max-width: 260px;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
|
||||
transform: translate(100%);
|
||||
background: #fff;
|
||||
z-index: 40000;
|
||||
}
|
||||
|
||||
.show {
|
||||
transition: all 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
|
||||
|
||||
.right-panel-background {
|
||||
z-index: 20000;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
transform: translate(0);
|
||||
}
|
||||
}
|
||||
|
||||
.handle-button {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
z-index: 0;
|
||||
pointer-events: auto;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
line-height: 48px;
|
||||
top: 45%;
|
||||
background: rgb(24, 144, 255);
|
||||
i {
|
||||
font-size: 24px;
|
||||
line-height: 48px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
77
src/layout/components/screenfull/index.vue
Normal file
77
src/layout/components/screenfull/index.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="screen-full" @click="onClick">
|
||||
<i
|
||||
:title="isFullscreen ? '退出全屏' : '全屏'"
|
||||
:class="
|
||||
isFullscreen
|
||||
? 'iconfont team-iconexit-fullscreen'
|
||||
: 'iconfont team-iconfullscreen'
|
||||
"
|
||||
></i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import screenfull from "screenfull";
|
||||
import {
|
||||
ref,
|
||||
onBeforeMount,
|
||||
onUnmounted,
|
||||
defineComponent,
|
||||
onMounted,
|
||||
} from "vue";
|
||||
export default defineComponent({
|
||||
name: "screenfull",
|
||||
setup() {
|
||||
let isFullscreen = ref(false);
|
||||
|
||||
const onClick = () => {
|
||||
if (!screenfull.isEnabled) return;
|
||||
screenfull.toggle();
|
||||
};
|
||||
|
||||
const change = () => {
|
||||
isFullscreen.value = screenfull.isFullscreen;
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.on("change", change);
|
||||
}
|
||||
};
|
||||
|
||||
const destroy = () => {
|
||||
if (screenfull.isEnabled) {
|
||||
screenfull.off("change", change);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
destroy();
|
||||
});
|
||||
|
||||
return {
|
||||
isFullscreen,
|
||||
onClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.screen-full {
|
||||
width: 40px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
74
src/layout/components/setting/index.vue
Normal file
74
src/layout/components/setting/index.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<panel>
|
||||
<el-divider>界面显示</el-divider>
|
||||
<ul class="setting">
|
||||
<li>
|
||||
<span>灰色模式</span>
|
||||
<vxe-switch
|
||||
v-model="greyVal"
|
||||
open-label="开"
|
||||
close-label="关"
|
||||
@change="greyChange"
|
||||
></vxe-switch>
|
||||
</li>
|
||||
</ul>
|
||||
</panel>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import panel from "../panel/index.vue";
|
||||
import { onMounted, reactive, toRefs } from "vue";
|
||||
import { storageLocal } from "../../../utils/storage";
|
||||
export default {
|
||||
name: "setting",
|
||||
components: { panel },
|
||||
setup() {
|
||||
const localOperate = (key: string, value?: any, model?: string): any => {
|
||||
model && model === "set"
|
||||
? storageLocal.setItem(key, value)
|
||||
: storageLocal.getItem(key);
|
||||
};
|
||||
|
||||
const settings = reactive({
|
||||
greyVal: storageLocal.getItem("greyVal"),
|
||||
});
|
||||
|
||||
settings.greyVal === null
|
||||
? localOperate("greyVal", false, "set")
|
||||
: document.querySelector("html")?.setAttribute("class", "html-grey");
|
||||
|
||||
// 灰色模式设置
|
||||
const greyChange = ({ value }): void => {
|
||||
if (value) {
|
||||
localOperate("greyVal", true, "set");
|
||||
document.querySelector("html")?.setAttribute("class", "html-grey");
|
||||
} else {
|
||||
localOperate("greyVal", false, "set");
|
||||
document.querySelector("html")?.removeAttribute("class");
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(settings),
|
||||
localOperate,
|
||||
greyChange,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.setting {
|
||||
width: 100%;
|
||||
li {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 16px;
|
||||
}
|
||||
}
|
||||
:deep(.el-divider__text) {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
30
src/layout/components/sidebar/Link.vue
Normal file
30
src/layout/components/sidebar/Link.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<component :is="type" v-bind="linkProps(to)">
|
||||
<slot />
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, defineComponent } from "vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Link",
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const linkProps = (to) => {
|
||||
return {
|
||||
to: to,
|
||||
};
|
||||
};
|
||||
return {
|
||||
type: "router-link",
|
||||
linkProps,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
101
src/layout/components/sidebar/SidebarItem.vue
Normal file
101
src/layout/components/sidebar/SidebarItem.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<div v-if="!item.hidden">
|
||||
<template
|
||||
v-if="
|
||||
hasOneShowingChild(item.children, item) &&
|
||||
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
|
||||
!item.alwaysShow
|
||||
"
|
||||
>
|
||||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
|
||||
<el-menu-item
|
||||
:index="resolvePath(onlyOneChild.path)"
|
||||
:class="{ 'submenu-title-noDropdown': !isNest }"
|
||||
>
|
||||
<i :class="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" />
|
||||
<template #title>
|
||||
<span>{{ $t(onlyOneChild.meta.title) }}</span>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
</app-link>
|
||||
</template>
|
||||
|
||||
<el-submenu
|
||||
v-else
|
||||
ref="subMenu"
|
||||
:index="resolvePath(item.path)"
|
||||
popper-append-to-body
|
||||
>
|
||||
<template #title>
|
||||
<i :class="item.meta.icon"></i>
|
||||
<span>{{ $t(item.meta.title) }}</span>
|
||||
</template>
|
||||
<sidebar-item
|
||||
v-for="child in item.children"
|
||||
:key="child.path"
|
||||
:is-nest="true"
|
||||
:item="child"
|
||||
:base-path="resolvePath(child.path)"
|
||||
class="nest-menu"
|
||||
/>
|
||||
</el-submenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import path from "path";
|
||||
import AppLink from "./Link.vue";
|
||||
import { defineComponent, PropType, ref } from "vue";
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
export default defineComponent({
|
||||
name: "SidebarItem",
|
||||
components: { AppLink },
|
||||
props: {
|
||||
item: {
|
||||
type: Object as PropType<RouteRecordRaw>,
|
||||
required: true,
|
||||
},
|
||||
isNest: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
basePath: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const onlyOneChild = ref<RouteRecordRaw>({} as any);
|
||||
|
||||
function hasOneShowingChild(
|
||||
children: RouteRecordRaw[] = [],
|
||||
parent: RouteRecordRaw
|
||||
) {
|
||||
const showingChildren = children.filter((item) => {
|
||||
if (item.hidden) {
|
||||
return false;
|
||||
} else {
|
||||
onlyOneChild.value = item;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
if (showingChildren.length === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (showingChildren.length === 0) {
|
||||
onlyOneChild.value = { ...parent, path: "", noShowingChildren: true };
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const resolvePath = (routePath: string) => {
|
||||
return path.resolve(props.basePath, routePath);
|
||||
};
|
||||
|
||||
return { hasOneShowingChild, resolvePath, onlyOneChild };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
55
src/layout/components/sidebar/index.vue
Normal file
55
src/layout/components/sidebar/index.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<el-scrollbar wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
:default-active="activeMenu"
|
||||
:collapse="isCollapse"
|
||||
background-color="#304156"
|
||||
text-color="#bfcbd9"
|
||||
:unique-opened="false"
|
||||
active-text-color="#409EFF"
|
||||
:collapse-transition="false"
|
||||
mode="vertical"
|
||||
>
|
||||
<sidebar-item
|
||||
v-for="route in routes"
|
||||
:key="route.path"
|
||||
:item="route"
|
||||
:base-path="route.path"
|
||||
/>
|
||||
</el-menu>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useStore } from "vuex";
|
||||
import SidebarItem from "./SidebarItem.vue";
|
||||
import { algorithm } from "../../../utils/algorithm";
|
||||
|
||||
export default defineComponent({
|
||||
name: "sidebar",
|
||||
components: { SidebarItem },
|
||||
setup() {
|
||||
const router = useRouter().options.routes;
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const activeMenu = computed(() => {
|
||||
const { meta, path } = route;
|
||||
if (meta.activeMenu) {
|
||||
return meta.activeMenu;
|
||||
}
|
||||
return path;
|
||||
});
|
||||
|
||||
return {
|
||||
routes: computed(() => algorithm.increaseIndexes(router)),
|
||||
activeMenu,
|
||||
isCollapse: computed(() => !store.getters.sidebar.opened),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
51
src/layout/components/tag/index.vue
Normal file
51
src/layout/components/tag/index.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="tags">
|
||||
<el-tag
|
||||
size="medium"
|
||||
v-for="tag in tags"
|
||||
:key="tag.name"
|
||||
closable
|
||||
:type="tag.type"
|
||||
>{{ tag.name }}</el-tag
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang='ts'>
|
||||
import { ref, defineComponent, onUnmounted, onMounted } from "vue";
|
||||
export default defineComponent({
|
||||
name: "tag",
|
||||
setup() {
|
||||
let flag = ref(true);
|
||||
|
||||
const tags = ref([
|
||||
{ name: "首页", type: "info" },
|
||||
{ name: "基础管理", type: "info" },
|
||||
]);
|
||||
|
||||
return {
|
||||
tags,
|
||||
flag,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.tags {
|
||||
height: 32px;
|
||||
float: right;
|
||||
border: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: 0.18s;
|
||||
}
|
||||
:deep(.el-tag) {
|
||||
background-color: #fff;
|
||||
border: 1px solid #d0d7e7;
|
||||
margin-left: 4px;
|
||||
&:first-child {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user