feat: 🎸 layout三种布局重构完成
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import request from './request'
|
||||
|
||||
import config from '../config'
|
||||
import config from './config'
|
||||
|
||||
import { AxiosPromise, ResponseType } from 'axios'
|
||||
|
||||
|
||||
@@ -1,39 +1,9 @@
|
||||
/**
|
||||
* 全局配置
|
||||
* request全局配置
|
||||
*/
|
||||
import { ConfigOptions } from './types'
|
||||
|
||||
const config: ConfigOptions = {
|
||||
/**
|
||||
* 配置显示在浏览器标签的title
|
||||
*/
|
||||
title: 'vue-antdv-admin',
|
||||
|
||||
/**
|
||||
* 是否显示标签页
|
||||
*/
|
||||
has_tags: true,
|
||||
|
||||
/**
|
||||
* 是否显示logo
|
||||
*/
|
||||
show_logo: true,
|
||||
|
||||
/**
|
||||
* logo标题
|
||||
*/
|
||||
logo_title: 'vue-antdv-admin',
|
||||
|
||||
/**
|
||||
* 横纵布局 Classic(经典) Top(头部) LeftTop(左侧顶部)
|
||||
*/
|
||||
layout: 'Test',
|
||||
|
||||
/**
|
||||
* 主题色 light(明亮) dark(暗黑)
|
||||
*/
|
||||
theme: 'dark',
|
||||
|
||||
/**
|
||||
* api请求基础路径
|
||||
*/
|
||||
@@ -61,12 +31,7 @@ const config: ConfigOptions = {
|
||||
* 默认接口请求类型
|
||||
* 可选值:application/x-www-form-urlencoded multipart/form-data
|
||||
*/
|
||||
default_headers: 'application/json',
|
||||
|
||||
/**
|
||||
* 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
*/
|
||||
user_info: 'userInfo'
|
||||
default_headers: 'application/json'
|
||||
}
|
||||
|
||||
export default config
|
||||
9
src/pages/index/axios-config/config/types.d.ts
vendored
Normal file
9
src/pages/index/axios-config/config/types.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* request配置
|
||||
*/
|
||||
export interface ConfigOptions {
|
||||
base_url: object
|
||||
result_code: number | string
|
||||
default_headers: string
|
||||
request_timeout: number
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'
|
||||
|
||||
import { message } from 'ant-design-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
import qs from 'qs'
|
||||
|
||||
import config from '../config'
|
||||
import config from './config'
|
||||
|
||||
const { result_code, base_url } = config
|
||||
|
||||
@@ -37,12 +37,12 @@ service.interceptors.response.use(
|
||||
if (response.data.code === result_code) {
|
||||
return response.data
|
||||
} else {
|
||||
message.error(response.data.message)
|
||||
ElMessage.error(response.data.message)
|
||||
}
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
console.log('err' + error) // for debug
|
||||
message.error(error.message)
|
||||
ElMessage.error(error.message)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
16
src/pages/index/config/types.d.ts
vendored
16
src/pages/index/config/types.d.ts
vendored
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* 全局配置
|
||||
*/
|
||||
export interface ConfigOptions {
|
||||
title?: string
|
||||
has_tags: boolean
|
||||
show_logo: boolean
|
||||
logo_title: string
|
||||
base_url: object
|
||||
result_code: number | string
|
||||
default_headers: string
|
||||
request_timeout: number
|
||||
user_info: string
|
||||
layout: 'Classic' | 'Top' | 'LeftTop' | 'Test'
|
||||
theme: 'light' | 'dark'
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<template>
|
||||
<router-link :class="['app-logo', 'app-logo-' + theme]" to="/">
|
||||
<img :src="require('@/assets/img/logo.png')">
|
||||
<div v-if="show" class="sidebar-title">{{ title }}</div>
|
||||
</router-link>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch, PropType } from 'vue'
|
||||
import config from '_p/index/config'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Logo',
|
||||
props: {
|
||||
collapsed: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
required: true
|
||||
},
|
||||
theme: {
|
||||
type: String as PropType<'light' | 'dark'>,
|
||||
default: 'dark'
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const show = ref<boolean>(true)
|
||||
watch(
|
||||
() => props.collapsed,
|
||||
(collapsed: boolean) => {
|
||||
if (!collapsed) {
|
||||
setTimeout(() => {
|
||||
show.value = !collapsed
|
||||
}, 400)
|
||||
} else {
|
||||
show.value = !collapsed
|
||||
}
|
||||
}
|
||||
)
|
||||
return {
|
||||
show,
|
||||
title: config.title
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.app-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 18px;
|
||||
cursor: pointer;
|
||||
height: @topSilderHeight;
|
||||
max-width: 200px;
|
||||
img {
|
||||
width: 37px;
|
||||
height: 37px;
|
||||
}
|
||||
.sidebar-title {
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
transition: .5s;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
.app-logo-dark {
|
||||
background-color: @menuBg;
|
||||
.sidebar-title {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.app-logo-light {
|
||||
background-color: #fff;
|
||||
.sidebar-title {
|
||||
color: #000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,75 +0,0 @@
|
||||
<template>
|
||||
<div class="navbar">
|
||||
<hamburger :collapsed="collapsed" class="hamburger-container" @toggleClick="setCollapsed" />
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
|
||||
<div class="right-menu">
|
||||
<screenfull class="right-menu-item hover-effect" />
|
||||
|
||||
<user-info class="right-menu-item hover-effect" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import Hamburger from '_c/Hamburger/index.vue'
|
||||
import Breadcrumb from '_c/Breadcrumb/index.vue'
|
||||
import Screenfull from '_c/Screenfull/index.vue'
|
||||
import UserInfo from './UserInfo.vue'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
export default defineComponent({
|
||||
name: 'Navbar',
|
||||
components: {
|
||||
Hamburger,
|
||||
Breadcrumb,
|
||||
Screenfull,
|
||||
UserInfo
|
||||
},
|
||||
setup() {
|
||||
const collapsed = computed(() => appStore.collapsed)
|
||||
|
||||
function setCollapsed(collapsed: boolean): void {
|
||||
appStore.SetCollapsed(collapsed)
|
||||
}
|
||||
|
||||
return {
|
||||
collapsed,
|
||||
setCollapsed
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.navbar {
|
||||
.hamburger-container {
|
||||
line-height: @navbarHeight;
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
margin-left: 15px;
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, .025);
|
||||
}
|
||||
}
|
||||
.breadcrumb-container {
|
||||
float: left;
|
||||
}
|
||||
.right-menu {
|
||||
float: right;
|
||||
height: 100%;
|
||||
line-height: @navbarHeight;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
.right-menu-item {
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
height: 100%;
|
||||
font-size: 18px;
|
||||
color: #5a5e66;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,34 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<i v-if="icon.includes('el-icon')" :class="[icon, 'sub-el-icon', 'anticon']" />
|
||||
<svg-icon v-else :icon-class="icon" class="anticon" />
|
||||
<slot name="title">
|
||||
<span class="anticon-item">{{ title }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Item',
|
||||
props: {
|
||||
icon: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
},
|
||||
title: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.anticon-item {
|
||||
opacity: 1;
|
||||
transition: opacity .3s cubic-bezier(.645,.045,.355,1),width .3s cubic-bezier(.645,.045,.355,1);
|
||||
}
|
||||
</style>
|
||||
@@ -1,92 +0,0 @@
|
||||
import { ref } from 'vue'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import path from 'path'
|
||||
import { isExternal } from '@/utils/validate'
|
||||
// import { setSidebarItem } from './types'
|
||||
|
||||
export function setSidebarItem() {
|
||||
const onlyOneChild = ref<any>(null)
|
||||
|
||||
function hasOneShowingChild(children: RouteRecordRaw[] = [], parent: RouteRecordRaw): boolean {
|
||||
const showingChildren: RouteRecordRaw[] = children.filter((item: RouteRecordRaw) => {
|
||||
if (item.meta && item.meta.hidden) {
|
||||
return false
|
||||
} else {
|
||||
// Temp set(will be used if only has one showing child)
|
||||
onlyOneChild.value = item
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
// When there is only one child router, the child router is displayed by default
|
||||
if (showingChildren.length === 1) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Show parent if there are no child router to display
|
||||
if (showingChildren.length === 0) {
|
||||
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true }
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function resolvePath(basePath: string, routePath: string): string {
|
||||
if (isExternal(routePath)) {
|
||||
return routePath
|
||||
}
|
||||
return path.resolve(basePath, routePath)
|
||||
}
|
||||
|
||||
function treeFindRouter(tree: any[], func: Function, result: RouteRecordRaw[] = []): RouteRecordRaw[] {
|
||||
if (!tree) return []
|
||||
for (const data of tree) {
|
||||
result.push(data)
|
||||
if (func(data)) return result
|
||||
if (data.children) {
|
||||
const findChildren = treeFindRouter(data.children, func, result)
|
||||
if (findChildren.length) return findChildren
|
||||
}
|
||||
result.pop()
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
function getFullPath(arr: string[]): string[] {
|
||||
const result: string[] = []
|
||||
let basePath = '/'
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (i === arr.length) {
|
||||
continue
|
||||
}
|
||||
result.push(resolvePath(basePath, arr[i]))
|
||||
basePath = resolvePath(basePath, arr[i])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
function findCurrentRoute(routers: RouteRecordRaw[], path: string, basePath = '/', result: Array<any> = []): any {
|
||||
for (const item of routers) {
|
||||
if (!item.meta?.hidden) {
|
||||
const _basePath = resolvePath(basePath, item.path)
|
||||
if (_basePath === path && !item.children) {
|
||||
result.push(item)
|
||||
} else {
|
||||
if (item.children) {
|
||||
findCurrentRoute(item.children, path, _basePath, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result ? result[0] : null
|
||||
}
|
||||
|
||||
return {
|
||||
onlyOneChild,
|
||||
hasOneShowingChild,
|
||||
resolvePath,
|
||||
treeFindRouter,
|
||||
getFullPath,
|
||||
findCurrentRoute
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import type { Ref } from 'vue'
|
||||
import ref from 'vue'
|
||||
|
||||
export interface setSidebarItem = {
|
||||
onlyOneChild: Ref<any | null>
|
||||
hasOneShowingChild: Function<boolean>
|
||||
resolvePath: Function<string>
|
||||
treeFindPath: Function<string[]>
|
||||
getFullPath: Function<string[]>
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
.sidebar-container {
|
||||
height: 100%;
|
||||
}
|
||||
.has-logo {
|
||||
height: calc(~"100% - @{topSilderHeight}");
|
||||
}
|
||||
.menu-wrap {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import Silder from './index'
|
||||
|
||||
export default Silder
|
||||
@@ -1,176 +0,0 @@
|
||||
import { ref, defineComponent, PropType, computed, watch } from 'vue'
|
||||
// import { Menu } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { RouteRecordRaw, RouteLocationNormalizedLoaded } from 'vue-router'
|
||||
import Scrollbar from '_c/Scrollbar/index.vue'
|
||||
import Item from './Item.vue'
|
||||
import { permissionStore } from '_p/index/store/modules/permission'
|
||||
import { setSidebarItem } from './hooks/setSidebarItem'
|
||||
import { isExternal } from '@/utils/validate'
|
||||
import { findIndex } from '@/utils'
|
||||
import config from '_p/index/config'
|
||||
const { show_logo } = config
|
||||
|
||||
import './index.less'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Silder',
|
||||
components: {
|
||||
Scrollbar,
|
||||
Item
|
||||
},
|
||||
props: {
|
||||
collapsed: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: true
|
||||
},
|
||||
inlineIndent: {
|
||||
type: Number as PropType<number>,
|
||||
default: 24
|
||||
},
|
||||
forceSubMenuRender: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
default: false
|
||||
},
|
||||
mode: {
|
||||
type: String as PropType<'vertical' | 'horizontal' | 'vertical-right' | 'inline'>,
|
||||
default: 'inline'
|
||||
},
|
||||
theme: {
|
||||
type: String as PropType<'light' | 'dark'>,
|
||||
default: 'dark'
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const { currentRoute, push } = useRouter()
|
||||
const { resolvePath, treeFindRouter, getFullPath, findCurrentRoute } = setSidebarItem()
|
||||
const routers = computed((): RouteRecordRaw[] => {
|
||||
return permissionStore.routers
|
||||
})
|
||||
const selectedKeys = ref<string[]>([])
|
||||
const openKeys = ref<string[]>([])
|
||||
const activeMenuName = ref<string>('')
|
||||
|
||||
watch(
|
||||
() => currentRoute.value,
|
||||
(route: RouteLocationNormalizedLoaded) => {
|
||||
setSelectedKeys(route)
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.collapsed,
|
||||
(collapsed: boolean) => {
|
||||
setOpenKeys(currentRoute.value, collapsed)
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
function handleOpenChange(keyArr: string[]) {
|
||||
// 需要自己管理openKeys
|
||||
openKeys.value = keyArr
|
||||
}
|
||||
|
||||
function setOpenKeys(route: RouteLocationNormalizedLoaded, collapsed: boolean) {
|
||||
let currentRoute: any = null
|
||||
if (route.meta.activeMenu) {
|
||||
currentRoute = findCurrentRoute(routers.value, route.meta.activeMenu)
|
||||
} else {
|
||||
currentRoute = route
|
||||
}
|
||||
const parentRoute: RouteRecordRaw[] = treeFindRouter(permissionStore.routers, (data: any) => data.name === currentRoute.name)
|
||||
openKeys.value = collapsed ? [] : getFullPath(parentRoute.map((v: RouteRecordRaw) => v.path))
|
||||
}
|
||||
|
||||
function setSelectedKeys(route: RouteLocationNormalizedLoaded) {
|
||||
const { meta, path, name } = route
|
||||
activeMenuName.value = name as string
|
||||
if (meta.activeMenu) {
|
||||
selectedKeys.value = [meta.activeMenu]
|
||||
return
|
||||
}
|
||||
selectedKeys.value = [path]
|
||||
}
|
||||
|
||||
function highlightMenu(className: string, basePath: string) {
|
||||
const parentRoute: RouteRecordRaw[] = treeFindRouter(permissionStore.routers, (data: any) => data.name === currentRoute.value.name)
|
||||
const parentFullPath: string[] = getFullPath(parentRoute.map((v: RouteRecordRaw) => v.path))
|
||||
return findIndex(parentFullPath, (item: string) => item === basePath) !== -1 ? className : ''
|
||||
}
|
||||
|
||||
function handleMenuClick({ key }: any) {
|
||||
console.log(key)
|
||||
if (isExternal(key)) {
|
||||
window.open(key)
|
||||
} else {
|
||||
push({ path: key })
|
||||
}
|
||||
}
|
||||
|
||||
// function renderMenu(routers: RouteRecordRaw[], basePath = '/') {
|
||||
// if (routers && routers.length) {
|
||||
// return routers.map((item: RouteRecordRaw) => {
|
||||
// if (!item.meta?.hidden) {
|
||||
// const _basePath = resolvePath(basePath, item.path)
|
||||
// const { onlyOneChild, hasOneShowingChild } = setSidebarItem()
|
||||
// if (hasOneShowingChild(item.children, item) && (!onlyOneChild.value.children || onlyOneChild.value.noShowingChildren) && !item.meta?.alwaysShow) {
|
||||
// return (
|
||||
// <Menu.Item key={resolvePath(_basePath, onlyOneChild.value.path)} v-slots={{
|
||||
// default: () => [
|
||||
// <Item
|
||||
// icon={onlyOneChild.value.meta && onlyOneChild.value.meta.icon}
|
||||
// title={onlyOneChild.value.meta?.title}
|
||||
// />
|
||||
// ]
|
||||
// }}>
|
||||
// </Menu.Item>
|
||||
// )
|
||||
// } else {
|
||||
// return (
|
||||
// <Menu.SubMenu
|
||||
// key={_basePath}
|
||||
// class={highlightMenu(props.theme + '-active-item', _basePath)}
|
||||
// popupClassName={highlightMenu(props.theme + '-popup-active-item', _basePath)}
|
||||
// v-slots={{
|
||||
// title: () => [
|
||||
// <Item
|
||||
// icon={item.meta && item.meta.icon}
|
||||
// title={item.meta?.title}
|
||||
// />
|
||||
// ]
|
||||
// }}
|
||||
// >
|
||||
// {renderMenu(item.children as any, _basePath)}
|
||||
// </Menu.SubMenu>
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// return () => {
|
||||
// return (
|
||||
// // <div class={{ 'has-logo': show_logo, 'sidebar-container': true }}>
|
||||
// // <scrollbar class='menu-wrap'>
|
||||
// // <Menu
|
||||
// // selectedKeys={selectedKeys.value}
|
||||
// // openKeys={openKeys.value}
|
||||
// // theme={props.theme}
|
||||
// // mode={props.mode}
|
||||
// // onClick={handleMenuClick}
|
||||
// // onOpenChange={handleOpenChange}
|
||||
// // >
|
||||
// // {renderMenu(routers.value)}
|
||||
// // </Menu>
|
||||
// // </scrollbar>
|
||||
// // </div>
|
||||
// )
|
||||
// }
|
||||
}
|
||||
})
|
||||
@@ -1,377 +0,0 @@
|
||||
<template>
|
||||
<div ref="wrapper" class="tags-view-container">
|
||||
<span class="move-btn prev-btn">
|
||||
<a-button @click="move(-200)">
|
||||
<template #icon><LeftOutlined /></template>
|
||||
</a-button>
|
||||
</span>
|
||||
<scroll-pane ref="scrollPane" class="tags-view-wrapper">
|
||||
<div>
|
||||
<router-link
|
||||
v-for="tag in visitedViews"
|
||||
:ref="setTagRef"
|
||||
:key="tag.path"
|
||||
:class="isActive(tag) ? 'active' : ''"
|
||||
:to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
|
||||
tag="span"
|
||||
class="tags-view-item"
|
||||
@click.middle="closeSelectedTag(tag)"
|
||||
@contextmenu.prevent="openMenu(tag, $event)"
|
||||
>
|
||||
{{ tag.title }}
|
||||
<CloseOutlined v-if="!tag.meta.affix" class="icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
|
||||
</router-link>
|
||||
</div>
|
||||
</scroll-pane>
|
||||
<span class="move-btn next-btn">
|
||||
<a-button @click="move(200)">
|
||||
<template #icon><RightOutlined /></template>
|
||||
</a-button>
|
||||
</span>
|
||||
<ul v-show="visible" :style="{left: left + 'px', top: top + 'px'}" class="contextmenu">
|
||||
<li @click="refreshSelectedTag(selectedTag)">
|
||||
刷新
|
||||
</li>
|
||||
<li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">
|
||||
关闭
|
||||
</li>
|
||||
<li @click="closeOthersTags">
|
||||
关闭其他
|
||||
</li>
|
||||
<li @click="closeAllTags(selectedTag)">
|
||||
关闭全部
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import ScrollPane from '_c/ScrollPane/index.vue'
|
||||
import path from 'path'
|
||||
import { defineComponent, ref, unref, computed, watch, onMounted, nextTick } from 'vue'
|
||||
import { tagsViewStore } from '_p/index/store/modules/tagsView'
|
||||
import { permissionStore } from '_p/index/store/modules/permission'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { RouteLocationNormalizedLoaded, RouteRecordRaw } from 'vue-router'
|
||||
// import { LeftOutlined, RightOutlined, CloseOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'TagsView',
|
||||
components: {
|
||||
ScrollPane,
|
||||
// CloseOutlined,
|
||||
// LeftOutlined,
|
||||
// RightOutlined
|
||||
},
|
||||
setup() {
|
||||
const { currentRoute, push, replace } = useRouter()
|
||||
const wrapper = ref<HTMLElement | null>(null)
|
||||
const scrollPane = ref<HTMLElement | null>(null)
|
||||
const visible = ref<boolean>(false)
|
||||
const top = ref<number>(0)
|
||||
const left = ref<number>(0)
|
||||
const selectedTag = ref<any>({})
|
||||
const affixTags = ref<any[]>([])
|
||||
const visitedViews = computed(() => tagsViewStore.visitedViews)
|
||||
const routers = computed(() => permissionStore.routers)
|
||||
|
||||
const tagRefs = ref<any[]>([])
|
||||
|
||||
function setTagRef(el: any): void {
|
||||
tagRefs.value.push(el)
|
||||
}
|
||||
|
||||
function isActive(route: RouteLocationNormalizedLoaded): boolean {
|
||||
return route.path === currentRoute.value.path
|
||||
}
|
||||
|
||||
function filterAffixTags(routes: RouteRecordRaw[], basePath = '/'): any[] {
|
||||
let tags: any[] = []
|
||||
routes.forEach((route: RouteRecordRaw) => {
|
||||
if (route.meta && route.meta.affix) {
|
||||
const tagPath = path.resolve(basePath, route.path)
|
||||
tags.push({
|
||||
fullPath: tagPath,
|
||||
path: tagPath,
|
||||
name: route.name,
|
||||
meta: { ...route.meta }
|
||||
})
|
||||
}
|
||||
if (route.children) {
|
||||
const tempTags: any[] = filterAffixTags(route.children, route.path)
|
||||
if (tempTags.length >= 1) {
|
||||
tags = [...tags, ...tempTags]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return tags
|
||||
}
|
||||
|
||||
function initTags(): void {
|
||||
affixTags.value = filterAffixTags(routers.value)
|
||||
const affixTagArr: any[] = affixTags.value
|
||||
for (const tag of affixTagArr) {
|
||||
// Must have tag name
|
||||
if (tag.name) {
|
||||
tagsViewStore.addVisitedView(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addTags(): void | boolean {
|
||||
const { name } = currentRoute.value
|
||||
if (name) {
|
||||
tagsViewStore.addView(currentRoute.value)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function moveToCurrentTag() {
|
||||
// TODO 要手动清除tagRefs,不然会一直重复,后续看看有没有什么解决办法
|
||||
tagRefs.value = []
|
||||
const tags = unref(tagRefs)
|
||||
nextTick(() => {
|
||||
for (const tag of tags) {
|
||||
if (tag && tag.to.path === currentRoute.value.path) {
|
||||
(unref(scrollPane) as any).moveToTarget(tag)
|
||||
// when query is different then update
|
||||
if (tag.to.fullPath !== currentRoute.value.fullPath) {
|
||||
tagsViewStore.updateVisitedView(currentRoute.value)
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function refreshSelectedTag(view: RouteLocationNormalizedLoaded) {
|
||||
await tagsViewStore.delCachedView()
|
||||
const { fullPath } = view
|
||||
nextTick(() => {
|
||||
replace({
|
||||
path: '/redirect' + fullPath
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function closeSelectedTag(view: RouteLocationNormalizedLoaded) {
|
||||
const views: any = await tagsViewStore.delView(view)
|
||||
if (isActive(view)) {
|
||||
toLastView(views.visitedViews)
|
||||
}
|
||||
}
|
||||
|
||||
function closeOthersTags() {
|
||||
push(selectedTag.value)
|
||||
tagsViewStore.delOthersViews(selectedTag.value).then(() => {
|
||||
moveToCurrentTag()
|
||||
})
|
||||
}
|
||||
|
||||
async function closeAllTags(view: RouteLocationNormalizedLoaded) {
|
||||
const views: any = await tagsViewStore.delAllViews()
|
||||
if (affixTags.value.some(tag => tag.path === view.path)) {
|
||||
return
|
||||
}
|
||||
toLastView(views.visitedViews)
|
||||
}
|
||||
|
||||
function toLastView(visitedViews: RouteLocationNormalizedLoaded[]) {
|
||||
const latestView = visitedViews.slice(-1)[0]
|
||||
setTimeout(() => {
|
||||
if (latestView) {
|
||||
push(latestView)
|
||||
} else {
|
||||
// You can set another route
|
||||
push('/')
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function openMenu(tag: RouteLocationNormalizedLoaded, e: any) {
|
||||
const menuMinWidth = 105
|
||||
const offsetLeft: number = (unref(wrapper) as any).getBoundingClientRect().left // container margin left
|
||||
const offsetWidth: number = (unref(wrapper) as any).offsetWidth // container width
|
||||
const maxLeft: number = offsetWidth - menuMinWidth// left boundary
|
||||
const itemLeft: number = e.clientX - offsetLeft + 4
|
||||
|
||||
if (itemLeft > maxLeft) {
|
||||
left.value = maxLeft
|
||||
} else {
|
||||
left.value = itemLeft
|
||||
}
|
||||
top.value = e.offsetY
|
||||
|
||||
visible.value = true
|
||||
selectedTag.value = tag
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
visible.value = false
|
||||
}
|
||||
|
||||
function move(to: number) {
|
||||
(unref(scrollPane) as any).moveTo(to)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initTags()
|
||||
addTags()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => currentRoute.value,
|
||||
() => {
|
||||
addTags()
|
||||
moveToCurrentTag()
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => visible.value,
|
||||
(visible: boolean) => {
|
||||
if (visible) {
|
||||
document.body.addEventListener('click', closeMenu)
|
||||
} else {
|
||||
document.body.removeEventListener('click', closeMenu)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
wrapper, scrollPane,
|
||||
visible, top, left,
|
||||
selectedTag, affixTags,
|
||||
visitedViews, routers,
|
||||
tagRefs, setTagRef,
|
||||
isActive,
|
||||
filterAffixTags,
|
||||
initTags,
|
||||
addTags,
|
||||
moveToCurrentTag,
|
||||
refreshSelectedTag,
|
||||
closeSelectedTag,
|
||||
closeOthersTags,
|
||||
closeAllTags,
|
||||
toLastView,
|
||||
openMenu,
|
||||
closeMenu,
|
||||
move
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.tags-view-container {
|
||||
height: @tagsViewHeight;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
|
||||
position: relative;
|
||||
display: flex;
|
||||
z-index: 100;
|
||||
&::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-top: #d8dce5;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
.move-btn {
|
||||
display: inline-block;
|
||||
width: @tagsViewHeight;
|
||||
height: @tagsViewHeight;
|
||||
line-height: @tagsViewHeight;
|
||||
text-align: center;
|
||||
.ant-btn {
|
||||
width: @tagsViewHeight;
|
||||
height: @tagsViewHeight;
|
||||
line-height: @tagsViewHeight;
|
||||
}
|
||||
}
|
||||
.tags-view-wrapper {
|
||||
width: calc(~"100% - 78px");
|
||||
.tags-view-item {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
border: 1px solid #d8dce5;
|
||||
color: #495060;
|
||||
background: #fff;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
&:last-of-type {
|
||||
margin-right: 4px;
|
||||
}
|
||||
&.active {
|
||||
background-color: #304156;
|
||||
color: #fff;
|
||||
border-color: #304156;
|
||||
&::before {
|
||||
content: '';
|
||||
background: #fff;
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.icon-close {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
line-height: 16px;
|
||||
transition: all .3s cubic-bezier(.645, .045, .355, 1);
|
||||
transform-origin: 100% 50%;
|
||||
margin-left: 5px;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
&:before {
|
||||
transform: scale(.6);
|
||||
display: inline-block;
|
||||
}
|
||||
&:hover {
|
||||
background-color: #b4bccc;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.contextmenu {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
z-index: 200;
|
||||
position: absolute;
|
||||
list-style-type: none;
|
||||
padding: 5px 0;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 7px 16px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@{deep}(.scrollbar__view) {
|
||||
height: @tagsViewHeight;
|
||||
line-height: @tagsViewHeight;
|
||||
}
|
||||
</style>
|
||||
@@ -1,68 +0,0 @@
|
||||
<template>
|
||||
<el-dropdown class="avatar-container" :trigger="['hover']">
|
||||
<div>
|
||||
<div class="avatar-wrapper">
|
||||
<img :src="require('@/assets/img/avatar.gif')" class="user-avatar">
|
||||
<span class="name-item">管理员</span>
|
||||
</div>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item key="1">
|
||||
<router-link to="/">
|
||||
首页
|
||||
</router-link>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item key="2">
|
||||
<span style="display: block;" @click="loginOut">退出登录</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { resetRouter } from '_p/index/router'
|
||||
import wsCache from '@/cache'
|
||||
import { useRouter } from 'vue-router'
|
||||
export default defineComponent({
|
||||
name: 'UserInfo',
|
||||
setup() {
|
||||
const { replace } = useRouter()
|
||||
async function loginOut(): Promise<void> {
|
||||
wsCache.clear()
|
||||
await resetRouter() // 重置静态路由表
|
||||
// this.$store.dispatch('delAllViews') // 删除所有的tags标签页
|
||||
replace('/login')
|
||||
}
|
||||
return {
|
||||
loginOut
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.avatar-container {
|
||||
margin-right: 30px;
|
||||
padding: 0 10px;
|
||||
.avatar-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
.user-avatar {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.name-item {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,29 +1,26 @@
|
||||
<template>
|
||||
<div class="app-wrapper">
|
||||
<component :is="component" />
|
||||
<component :is="layout" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// import Classic from './modules/Classic.vue'
|
||||
// import Top from './modules/Top.vue'
|
||||
// import LeftTop from './modules/LeftTop.vue'
|
||||
import Test from './modules/Test.vue'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import config from '_p/index/config'
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import Classic from './modules/Classic.vue'
|
||||
import Top from './modules/Top.vue'
|
||||
import LeftTop from './modules/LeftTop.vue'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
export default defineComponent({
|
||||
name: 'Layout',
|
||||
components: {
|
||||
// Classic,
|
||||
// Top,
|
||||
// LeftTop,
|
||||
Test
|
||||
Classic,
|
||||
Top,
|
||||
LeftTop
|
||||
},
|
||||
setup() {
|
||||
const { layout } = config
|
||||
const component = ref<string>(layout)
|
||||
const layout = computed(() => appStore.layout)
|
||||
return {
|
||||
component
|
||||
layout
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,112 +1,251 @@
|
||||
<template>
|
||||
<a-layout class="app-wrapper">
|
||||
<a-layout-sider
|
||||
v-model:collapsed="collapsed"
|
||||
:trigger="null"
|
||||
collapsible
|
||||
:class="'ant-layout-sider--' + theme"
|
||||
class="sidebar-container-wrap"
|
||||
<div :class="classObj" class="app__wrap">
|
||||
<!-- Classic -->
|
||||
<div
|
||||
class="sidebar__wrap"
|
||||
:class="{'sidebar__wrap--collapsed': collapsed}"
|
||||
>
|
||||
<logo
|
||||
v-if="show_logo"
|
||||
v-if="showLogo && layout === 'Classic'"
|
||||
:collapsed="collapsed"
|
||||
:theme="theme"
|
||||
/>
|
||||
<silder
|
||||
:collapsed="collapsed"
|
||||
:theme="theme"
|
||||
/>
|
||||
</a-layout-sider>
|
||||
<a-layout>
|
||||
<a-layout-header :class="{'ant-layout-header-collapsed': collapsed}">
|
||||
<navbar />
|
||||
</a-layout-header>
|
||||
<a-layout-content :class="{'layout-content-has-tags':has_tags}">
|
||||
<scrollbar class="main-wrap">
|
||||
<tags-view :class="{'has-tags':has_tags, 'has-tags-collapsed': collapsed && has_tags}" />
|
||||
<app-main class="classic-module--wrap" />
|
||||
</scrollbar>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
<sider :layout="layout" mode="vertical" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="main__wrap"
|
||||
:class="{
|
||||
'main__wrap--collapsed': collapsed
|
||||
}"
|
||||
>
|
||||
<el-scrollbar
|
||||
class="main__wrap--content"
|
||||
:class="{
|
||||
'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
|
||||
'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
|
||||
'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="header__wrap"
|
||||
:class="{
|
||||
'header__wrap--fixed': fixedHeader,
|
||||
'header__wrap--collapsed': fixedHeader && collapsed
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-if="showNavbar"
|
||||
class="navbar__wrap"
|
||||
>
|
||||
<hamburger
|
||||
v-if="showHamburger"
|
||||
:collapsed="collapsed"
|
||||
class="hover-container"
|
||||
@toggleClick="setCollapsed"
|
||||
/>
|
||||
<breadcrumb v-if="showBreadcrumb" />
|
||||
<div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
|
||||
<screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
|
||||
<user-info v-if="showUserInfo" class="hover-container user-container" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="showTags"
|
||||
class="tags__wrap"
|
||||
>
|
||||
<tags-view />
|
||||
</div>
|
||||
</div>
|
||||
<app-main />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<!-- setting -->
|
||||
<setting />
|
||||
<!-- setting -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, PropType } from 'vue'
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
import Silder from '../components/Silder'
|
||||
import Navbar from '../components/Navbar.vue'
|
||||
|
||||
import AppMain from '../components/AppMain.vue'
|
||||
import TagsView from '../components/TagsView.vue'
|
||||
import Logo from '../components/Logo.vue'
|
||||
import Scrollbar from '_c/Scrollbar/index.vue'
|
||||
import config from '_p/index/config'
|
||||
const { show_logo, has_tags, theme } = config
|
||||
import TagsView from '_c/TagsView/index.vue'
|
||||
import Logo from '_c/Logo/index.vue'
|
||||
import Sider from '_c/Sider/index.vue'
|
||||
import Hamburger from '_c/Hamburger/index.vue'
|
||||
import Breadcrumb from '_c/Breadcrumb/index.vue'
|
||||
import Screenfull from '_c/Screenfull/index.vue'
|
||||
import UserInfo from '_c/UserInfo/index.vue'
|
||||
|
||||
import Setting from '_c/Setting/index.vue'
|
||||
export default defineComponent({
|
||||
name: 'Classic',
|
||||
components: {
|
||||
Silder,
|
||||
Navbar,
|
||||
Sider,
|
||||
Hamburger,
|
||||
Breadcrumb,
|
||||
Screenfull,
|
||||
UserInfo,
|
||||
AppMain,
|
||||
TagsView,
|
||||
Logo,
|
||||
Scrollbar
|
||||
},
|
||||
props: {
|
||||
theme: {
|
||||
type: String as PropType<'light' | 'dark'>,
|
||||
default: theme
|
||||
}
|
||||
Setting
|
||||
},
|
||||
setup() {
|
||||
const layout = computed(() => appStore.layout)
|
||||
const collapsed = computed(() => appStore.collapsed)
|
||||
const showLogo = computed(() => appStore.showLogo)
|
||||
const showTags = computed(() => appStore.showTags)
|
||||
const showBreadcrumb = computed(() => appStore.showBreadcrumb)
|
||||
const showHamburger = computed(() => appStore.showHamburger)
|
||||
const showScreenfull = computed(() => appStore.showScreenfull)
|
||||
const showUserInfo = computed(() => appStore.showUserInfo)
|
||||
const showNavbar = computed(() => appStore.showNavbar)
|
||||
// const fixedNavbar = computed(() => appStore.fixedNavbar)
|
||||
// const fixedTags = computed(() => appStore.fixedTags)
|
||||
const fixedHeader = computed(() => appStore.fixedHeader)
|
||||
|
||||
const classObj = computed(() => {
|
||||
const obj = {}
|
||||
obj[`app__wrap--${layout.value}`] = true
|
||||
return obj
|
||||
})
|
||||
|
||||
function setCollapsed(collapsed: boolean): void {
|
||||
appStore.SetCollapsed(collapsed)
|
||||
}
|
||||
|
||||
return {
|
||||
classObj,
|
||||
layout,
|
||||
collapsed,
|
||||
show_logo,
|
||||
has_tags
|
||||
showLogo,
|
||||
showTags,
|
||||
showBreadcrumb,
|
||||
showHamburger,
|
||||
showScreenfull,
|
||||
showUserInfo,
|
||||
showNavbar,
|
||||
fixedHeader,
|
||||
// fixedNavbar,
|
||||
// fixedTags,
|
||||
setCollapsed
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(.ant-layout-header) {
|
||||
line-height: @navbarHeight;
|
||||
height: @navbarHeight;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: @menuWidth;
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.ant-layout-sider--light {
|
||||
background: @menuLightBg;
|
||||
}
|
||||
.ant-layout-sider--dark {
|
||||
background: @menuBg;
|
||||
}
|
||||
.ant-layout-content {
|
||||
margin-top: @navbarHeight;
|
||||
.mian-wrap {
|
||||
background-color: @contentBg;
|
||||
.app__wrap {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
.sidebar__wrap {
|
||||
position: fixed;
|
||||
width: @menuWidth;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
transition: width 0.2s;
|
||||
}
|
||||
.sidebar__wrap--collapsed {
|
||||
width: @menuMinWidth;
|
||||
@{deep}(.anticon-item) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.main__wrap {
|
||||
position: absolute;
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: @menuWidth;
|
||||
transition: all 0.2s;
|
||||
z-index: 1;
|
||||
.header__wrap {
|
||||
transition: all 0.2s;
|
||||
.navbar__wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @navbarHeight;
|
||||
padding: 0 20px 0 15px;
|
||||
position: relative;
|
||||
background: @contentBg;
|
||||
&:after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-top: 1px solid #d8dce5;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
@{deep}(.hover-container) {
|
||||
transition: background 0.2s;
|
||||
height: 100%;
|
||||
line-height: @navbarHeight + 5px;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
.navbar__wrap--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @navbarHeight;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 20px;
|
||||
@{deep}(.screenfull-container),
|
||||
@{deep}(.user-container) {
|
||||
line-height: @navbarHeight !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// content样式
|
||||
.main__wrap--content {
|
||||
height: 100%;
|
||||
@{deep}(.el-scrollbar__wrap) {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
// content样式
|
||||
}
|
||||
.main__wrap--collapsed {
|
||||
width: calc(~"100% - @{menuMinWidth}");
|
||||
left: @menuMinWidth;
|
||||
}
|
||||
}
|
||||
.layout-content-has-tags {
|
||||
margin-top: @navbarHeight + @tagsViewHeight;
|
||||
}
|
||||
.has-tags {
|
||||
position: fixed;
|
||||
top: @navbarHeight;
|
||||
left: @menuWidth;
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.ant-layout-header-collapsed,
|
||||
.has-tags-collapsed {
|
||||
left: 80px;
|
||||
width: calc(~"100% - 80px");
|
||||
|
||||
// 经典模式
|
||||
.app__wrap--Classic {
|
||||
.main__wrap--fixed--all {
|
||||
margin-top: @navbarHeight + @tagsViewHeight !important;
|
||||
height: calc(~"100% - @{navbarHeight} - @{tagsViewHeight}") !important;
|
||||
}
|
||||
.main__wrap--fixed--nav {
|
||||
margin-top: @navbarHeight !important;
|
||||
height: calc(~"100% - @{navbarHeight}") !important;
|
||||
}
|
||||
.main__wrap--fixed--tags {
|
||||
margin-top: @tagsViewHeight !important;
|
||||
height: calc(~"100% - @{tagsViewHeight}") !important;
|
||||
}
|
||||
.header__wrap--fixed {
|
||||
position: fixed !important;
|
||||
width: calc(~"100% - @{menuWidth}") !important;
|
||||
top: 0 !important;
|
||||
left: @menuWidth !important;
|
||||
z-index: 200;
|
||||
}
|
||||
.header__wrap--collapsed {
|
||||
width: calc(~"100% - @{menuMinWidth}") !important;
|
||||
left: @menuMinWidth !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,97 +1,157 @@
|
||||
<template>
|
||||
<a-layout>
|
||||
<a-layout-header :class="'ant-layout-header--' + silderTheme">
|
||||
<div :class="classObj" class="app__wrap">
|
||||
<!-- Classic -->
|
||||
<div
|
||||
class="sidebar__wrap"
|
||||
:class="{'sidebar__wrap--collapsed': collapsed}"
|
||||
>
|
||||
<logo
|
||||
v-if="show_logo"
|
||||
:theme="silderTheme"
|
||||
v-if="showLogo && layout === 'Classic'"
|
||||
:collapsed="collapsed"
|
||||
/>
|
||||
<silder
|
||||
:theme="silderTheme"
|
||||
mode="horizontal"
|
||||
class="header-silder--wrap"
|
||||
/>
|
||||
<div class="right-menu">
|
||||
<screenfull class="right-menu-item hover-effect screenfull-item" />
|
||||
<sider :layout="layout" mode="vertical" />
|
||||
</div>
|
||||
<!-- Classic -->
|
||||
|
||||
<user-info class="right-menu-item hover-effect" />
|
||||
</div>
|
||||
</a-layout-header>
|
||||
<a-layout class="layout-content">
|
||||
<a-layout-sider
|
||||
v-model:collapsed="collapsed"
|
||||
:trigger="null"
|
||||
collapsible
|
||||
:class="'ant-layout-sider--' + theme"
|
||||
class="sidebar-container-wrap"
|
||||
>
|
||||
<silder
|
||||
<!-- Top -->
|
||||
<div v-if="layout !== 'Classic'" class="sidebar__wrap--Top">
|
||||
<div>
|
||||
<logo
|
||||
v-if="showLogo"
|
||||
:collapsed="collapsed"
|
||||
:theme="theme"
|
||||
class="left-sider-wrap"
|
||||
/>
|
||||
</a-layout-sider>
|
||||
<a-layout>
|
||||
<div class="navbar-wrap">
|
||||
<hamburger :collapsed="collapsed" class="hamburger-container" @toggleClick="setCollapsed" />
|
||||
<breadcrumb class="breadcrumb-container" />
|
||||
</div>
|
||||
<div v-if="layout === 'Top'" class="sidebar__item--Top">
|
||||
<sider :layout="layout" mode="horizontal" />
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
|
||||
<screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
|
||||
<user-info v-if="showUserInfo" class="hover-container user-container" />
|
||||
</div>
|
||||
<a-layout-content :class="{'layout-content-has-tags':has_tags}">
|
||||
<scrollbar class="main-wrap">
|
||||
<tags-view :class="{'has-tags':has_tags, 'has-tags-collapsed': collapsed && has_tags}" />
|
||||
<app-main class="classic-module--wrap" />
|
||||
</scrollbar>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</a-layout>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Top -->
|
||||
|
||||
<div
|
||||
class="main__wrap"
|
||||
:class="{
|
||||
'main__wrap--collapsed': collapsed
|
||||
}"
|
||||
>
|
||||
<el-scrollbar
|
||||
class="main__wrap--content"
|
||||
:class="{
|
||||
'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
|
||||
'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
|
||||
'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="header__wrap"
|
||||
:class="{
|
||||
'header__wrap--fixed': fixedHeader,
|
||||
'header__wrap--collapsed': fixedHeader && collapsed
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-if="showNavbar && layout !== 'Top'"
|
||||
class="navbar__wrap"
|
||||
>
|
||||
<hamburger
|
||||
v-if="showHamburger"
|
||||
:collapsed="collapsed"
|
||||
class="hover-container"
|
||||
@toggleClick="setCollapsed"
|
||||
/>
|
||||
<breadcrumb v-if="showBreadcrumb" />
|
||||
<!-- <div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
|
||||
<screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
|
||||
<user-info v-if="showUserInfo" class="hover-container user-container" />
|
||||
</div> -->
|
||||
</div>
|
||||
<div
|
||||
v-if="showTags"
|
||||
class="tags__wrap"
|
||||
>
|
||||
<tags-view />
|
||||
</div>
|
||||
</div>
|
||||
<app-main />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<!-- setting -->
|
||||
<setting />
|
||||
<!-- setting -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from 'vue'
|
||||
import Logo from '../components/Logo.vue'
|
||||
import Silder from '../components/Silder'
|
||||
import UserInfo from '../components/UserInfo.vue'
|
||||
import TagsView from '../components/TagsView.vue'
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
|
||||
import AppMain from '../components/AppMain.vue'
|
||||
import Screenfull from '_c/Screenfull/index.vue'
|
||||
import Scrollbar from '_c/Scrollbar/index.vue'
|
||||
import TagsView from '_c/TagsView/index.vue'
|
||||
import Logo from '_c/Logo/index.vue'
|
||||
import Sider from '_c/Sider/index.vue'
|
||||
import Hamburger from '_c/Hamburger/index.vue'
|
||||
import Breadcrumb from '_c/Breadcrumb/index.vue'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
import config from '_p/index/config'
|
||||
const { show_logo, has_tags, theme } = config
|
||||
import Screenfull from '_c/Screenfull/index.vue'
|
||||
import UserInfo from '_c/UserInfo/index.vue'
|
||||
|
||||
import Setting from '_c/Setting/index.vue'
|
||||
export default defineComponent({
|
||||
name: 'LeftTop',
|
||||
components: {
|
||||
Logo,
|
||||
Silder,
|
||||
UserInfo,
|
||||
TagsView,
|
||||
AppMain,
|
||||
Screenfull,
|
||||
Scrollbar,
|
||||
Sider,
|
||||
Hamburger,
|
||||
Breadcrumb
|
||||
},
|
||||
props: {
|
||||
theme: {
|
||||
type: String as PropType<'light' | 'dark'>,
|
||||
default: theme
|
||||
},
|
||||
silderTheme: {
|
||||
type: String as PropType<'light' | 'dark'>,
|
||||
default: 'light'
|
||||
}
|
||||
Breadcrumb,
|
||||
Screenfull,
|
||||
UserInfo,
|
||||
AppMain,
|
||||
TagsView,
|
||||
Logo,
|
||||
Setting
|
||||
},
|
||||
setup() {
|
||||
const layout = computed(() => appStore.layout)
|
||||
const collapsed = computed(() => appStore.collapsed)
|
||||
const showLogo = computed(() => appStore.showLogo)
|
||||
const showTags = computed(() => appStore.showTags)
|
||||
const showBreadcrumb = computed(() => appStore.showBreadcrumb)
|
||||
const showHamburger = computed(() => appStore.showHamburger)
|
||||
const showScreenfull = computed(() => appStore.showScreenfull)
|
||||
const showUserInfo = computed(() => appStore.showUserInfo)
|
||||
const showNavbar = computed(() => appStore.showNavbar)
|
||||
// const fixedNavbar = computed(() => appStore.fixedNavbar)
|
||||
// const fixedTags = computed(() => appStore.fixedTags)
|
||||
const fixedHeader = computed(() => appStore.fixedHeader)
|
||||
|
||||
const classObj = computed(() => {
|
||||
const obj = {}
|
||||
obj[`app__wrap--${layout.value}`] = true
|
||||
return obj
|
||||
})
|
||||
|
||||
function setCollapsed(collapsed: boolean): void {
|
||||
appStore.SetCollapsed(collapsed)
|
||||
}
|
||||
|
||||
return {
|
||||
classObj,
|
||||
layout,
|
||||
collapsed,
|
||||
show_logo,
|
||||
has_tags,
|
||||
showLogo,
|
||||
showTags,
|
||||
showBreadcrumb,
|
||||
showHamburger,
|
||||
showScreenfull,
|
||||
showUserInfo,
|
||||
showNavbar,
|
||||
fixedHeader,
|
||||
// fixedNavbar,
|
||||
// fixedTags,
|
||||
setCollapsed
|
||||
}
|
||||
}
|
||||
@@ -99,87 +159,173 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(.ant-layout-header) {
|
||||
height: @topSilderHeight;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
position: fixed;
|
||||
.app__wrap {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 20;
|
||||
&--light {
|
||||
background: @menuLightBg;
|
||||
}
|
||||
&--dark {
|
||||
background: @menuBg;
|
||||
.screenfull-item,
|
||||
.name-item {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.header-silder--wrap {
|
||||
flex: 1;
|
||||
margin: 0 50px;
|
||||
height: 100% !important;
|
||||
.ant-menu-horizontal {
|
||||
height: @topSilderHeight;
|
||||
line-height: @topSilderHeight;
|
||||
border-bottom: 0;
|
||||
}
|
||||
.ant-menu-light {
|
||||
height: calc(~"@{topSilderHeight} - 4px");
|
||||
line-height: calc(~"@{topSilderHeight} - 2px");
|
||||
}
|
||||
}
|
||||
.right-menu {
|
||||
display: flex;
|
||||
.screenfull-item {
|
||||
line-height: @topSilderHeight;
|
||||
}
|
||||
.avatar-container {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-layout-sider--light {
|
||||
background: @menuLightBg;
|
||||
}
|
||||
.ant-layout-sider--dark {
|
||||
background: @menuBg;
|
||||
}
|
||||
.layout-content {
|
||||
margin-top: @topSilderHeight;
|
||||
height: calc(~"100vh - @{topSilderHeight}");
|
||||
.navbar-wrap {
|
||||
background: #fff;
|
||||
padding: 0 20px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
height: @navbarHeight;
|
||||
line-height: @navbarHeight;
|
||||
display: flex;
|
||||
}
|
||||
.layout-content-has-tags {
|
||||
margin-top: @tagsViewHeight;
|
||||
.mian-wrap {
|
||||
background-color: @contentBg;
|
||||
}
|
||||
}
|
||||
.left-sider-wrap {
|
||||
height: 100%;
|
||||
}
|
||||
.has-tags {
|
||||
.sidebar__wrap {
|
||||
position: fixed;
|
||||
top: @topSilderHeight + @navbarHeight;
|
||||
left: @menuWidth;
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
z-index: 20;
|
||||
transition: all 0.2s;
|
||||
width: @menuWidth;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
transition: width 0.2s;
|
||||
}
|
||||
.has-tags-collapsed {
|
||||
left: 80px;
|
||||
width: calc(~"100% - 80px");
|
||||
.sidebar__wrap--collapsed {
|
||||
width: @menuMinWidth;
|
||||
@{deep}(.anticon-item) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.main__wrap {
|
||||
position: absolute;
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: @menuWidth;
|
||||
transition: all 0.2s;
|
||||
z-index: 1;
|
||||
.header__wrap {
|
||||
transition: all 0.2s;
|
||||
.navbar__wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @navbarHeight;
|
||||
padding: 0 20px 0 15px;
|
||||
position: relative;
|
||||
background: @contentBg;
|
||||
&:after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-top: 1px solid #d8dce5;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
@{deep}(.hover-container) {
|
||||
transition: background 0.2s;
|
||||
height: 100%;
|
||||
line-height: @navbarHeight + 5px;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
.navbar__wrap--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @navbarHeight;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 20px;
|
||||
@{deep}(.screenfull-container),
|
||||
@{deep}(.user-container) {
|
||||
line-height: @navbarHeight !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// content样式
|
||||
.main__wrap--content {
|
||||
height: 100%;
|
||||
@{deep}(.el-scrollbar__wrap) {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
// content样式
|
||||
}
|
||||
.main__wrap--collapsed {
|
||||
width: calc(~"100% - @{menuMinWidth}");
|
||||
left: @menuMinWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// LeftTop模式
|
||||
.app__wrap--LeftTop {
|
||||
.main__wrap--fixed--all {
|
||||
margin-top: @navbarHeight + @tagsViewHeight !important;
|
||||
height: calc(~"100% - @{navbarHeight} - @{tagsViewHeight}") !important;
|
||||
}
|
||||
.main__wrap--fixed--nav {
|
||||
margin-top: @navbarHeight !important;
|
||||
height: calc(~"100% - @{navbarHeight}") !important;
|
||||
}
|
||||
.main__wrap--fixed--tags {
|
||||
margin-top: @tagsViewHeight !important;
|
||||
height: calc(~"100% - @{tagsViewHeight}") !important;
|
||||
}
|
||||
.header__wrap--fixed {
|
||||
position: fixed !important;
|
||||
width: calc(~"100% - @{menuWidth}") !important;
|
||||
top: @topSiderHeight !important;
|
||||
left: @menuWidth !important;
|
||||
z-index: 200;
|
||||
}
|
||||
.header__wrap--collapsed {
|
||||
width: calc(~"100% - @{menuMinWidth}") !important;
|
||||
left: @menuMinWidth !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 顶部模式
|
||||
.app__wrap--LeftTop {
|
||||
.sidebar__wrap--Top {
|
||||
height: @topSiderHeight;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
background-color: @topMenuBg;
|
||||
position: relative;
|
||||
&:after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-top: 1px solid #d8dce5;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
.sidebar__item--Top {
|
||||
flex: 1;
|
||||
margin: 0 50px;
|
||||
}
|
||||
.navbar__wrap--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @topSiderHeight;
|
||||
@{deep}(.hover-container) {
|
||||
transition: background 0.2s;
|
||||
height: 100%;
|
||||
line-height: @topSiderHeight;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app__wrap--LeftTop {
|
||||
.sidebar__wrap {
|
||||
top: @topSiderHeight;
|
||||
left: 0;
|
||||
height: calc(~"100% - @{topSiderHeight}");
|
||||
}
|
||||
.main__wrap {
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
left: @menuWidth;
|
||||
height: calc(~"100% - @{topSiderHeight}");
|
||||
top: @topSiderHeight;
|
||||
}
|
||||
.main__wrap--collapsed {
|
||||
width: calc(~"100% - @{menuMinWidth}");
|
||||
left: @menuMinWidth;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,128 +1,291 @@
|
||||
<template>
|
||||
<a-layout>
|
||||
<a-layout-header :class="'ant-layout-header--' + theme">
|
||||
<logo
|
||||
v-if="show_logo"
|
||||
:theme="theme"
|
||||
/>
|
||||
<silder
|
||||
:theme="theme"
|
||||
mode="horizontal"
|
||||
class="header-silder--wrap"
|
||||
/>
|
||||
<div class="right-menu">
|
||||
<screenfull class="right-menu-item hover-effect screenfull-item" />
|
||||
|
||||
<user-info class="right-menu-item hover-effect" />
|
||||
<div :class="classObj" class="app__wrap">
|
||||
<!-- Top -->
|
||||
<div class="sidebar__wrap--Top">
|
||||
<div>
|
||||
<logo
|
||||
v-if="showLogo"
|
||||
:collapsed="collapsed"
|
||||
/>
|
||||
</div>
|
||||
</a-layout-header>
|
||||
<a-layout-content :class="{'layout-content-has-tags':has_tags}">
|
||||
<scrollbar class="main-wrap">
|
||||
<tags-view :class="{'has-tags':has_tags}" />
|
||||
<app-main class="top-module--wrap" />
|
||||
</scrollbar>
|
||||
</a-layout-content>
|
||||
</a-layout>
|
||||
<div class="sidebar__item--Top">
|
||||
<sider :layout="layout" mode="horizontal" />
|
||||
</div>
|
||||
<div>
|
||||
<div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
|
||||
<screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
|
||||
<user-info v-if="showUserInfo" class="hover-container user-container" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Top -->
|
||||
|
||||
<div
|
||||
class="main__wrap"
|
||||
:class="{
|
||||
'main__wrap--collapsed': collapsed
|
||||
}"
|
||||
>
|
||||
<el-scrollbar
|
||||
class="main__wrap--content"
|
||||
:class="{
|
||||
'main__wrap--fixed--all': fixedHeader && showNavbar && showTags,
|
||||
'main__wrap--fixed--nav': fixedHeader && showNavbar && !showTags,
|
||||
'main__wrap--fixed--tags': fixedHeader && !showNavbar && showTags
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="header__wrap"
|
||||
:class="{
|
||||
'header__wrap--fixed': fixedHeader,
|
||||
'header__wrap--collapsed': fixedHeader && collapsed
|
||||
}"
|
||||
>
|
||||
<!-- <div
|
||||
v-if="showNavbar && layout !== 'Top'"
|
||||
class="navbar__wrap"
|
||||
>
|
||||
<hamburger
|
||||
v-if="showHamburger"
|
||||
:collapsed="collapsed"
|
||||
class="hover-container"
|
||||
@toggleClick="setCollapsed"
|
||||
/>
|
||||
<breadcrumb v-if="showBreadcrumb" />
|
||||
<div v-if="showScreenfull || showUserInfo" class="navbar__wrap--right">
|
||||
<screenfull v-if="showScreenfull" class="hover-container screenfull-container" />
|
||||
<user-info v-if="showUserInfo" class="hover-container user-container" />
|
||||
</div>
|
||||
</div> -->
|
||||
<div
|
||||
v-if="showTags"
|
||||
class="tags__wrap"
|
||||
>
|
||||
<tags-view />
|
||||
</div>
|
||||
</div>
|
||||
<app-main />
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
|
||||
<!-- setting -->
|
||||
<setting />
|
||||
<!-- setting -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
import Logo from '../components/Logo.vue'
|
||||
import Silder from '../components/Silder'
|
||||
import UserInfo from '../components/UserInfo.vue'
|
||||
import TagsView from '../components/TagsView.vue'
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
|
||||
import AppMain from '../components/AppMain.vue'
|
||||
import TagsView from '_c/TagsView/index.vue'
|
||||
import Logo from '_c/Logo/index.vue'
|
||||
import Sider from '_c/Sider/index.vue'
|
||||
// import Hamburger from '_c/Hamburger/index.vue'
|
||||
// import Breadcrumb from '_c/Breadcrumb/index.vue'
|
||||
import Screenfull from '_c/Screenfull/index.vue'
|
||||
import Scrollbar from '_c/Scrollbar/index.vue'
|
||||
import config from '_p/index/config'
|
||||
const { show_logo, has_tags, theme } = config
|
||||
import UserInfo from '_c/UserInfo/index.vue'
|
||||
|
||||
import Setting from '_c/Setting/index.vue'
|
||||
export default defineComponent({
|
||||
name: 'Top',
|
||||
components: {
|
||||
Logo,
|
||||
Silder,
|
||||
UserInfo,
|
||||
TagsView,
|
||||
AppMain,
|
||||
Sider,
|
||||
// Hamburger,
|
||||
// Breadcrumb,
|
||||
Screenfull,
|
||||
Scrollbar
|
||||
},
|
||||
props: {
|
||||
theme: {
|
||||
type: String as PropType<'light' | 'dark'>,
|
||||
default: theme
|
||||
}
|
||||
UserInfo,
|
||||
AppMain,
|
||||
TagsView,
|
||||
Logo,
|
||||
Setting
|
||||
},
|
||||
setup() {
|
||||
const layout = computed(() => appStore.layout)
|
||||
const collapsed = computed(() => appStore.collapsed)
|
||||
const showLogo = computed(() => appStore.showLogo)
|
||||
const showTags = computed(() => appStore.showTags)
|
||||
const showBreadcrumb = computed(() => appStore.showBreadcrumb)
|
||||
const showHamburger = computed(() => appStore.showHamburger)
|
||||
const showScreenfull = computed(() => appStore.showScreenfull)
|
||||
const showUserInfo = computed(() => appStore.showUserInfo)
|
||||
const showNavbar = computed(() => appStore.showNavbar)
|
||||
// const fixedNavbar = computed(() => appStore.fixedNavbar)
|
||||
// const fixedTags = computed(() => appStore.fixedTags)
|
||||
const fixedHeader = computed(() => appStore.fixedHeader)
|
||||
|
||||
const classObj = computed(() => {
|
||||
const obj = {}
|
||||
obj[`app__wrap--${layout.value}`] = true
|
||||
return obj
|
||||
})
|
||||
|
||||
function setCollapsed(collapsed: boolean): void {
|
||||
appStore.SetCollapsed(collapsed)
|
||||
}
|
||||
|
||||
return {
|
||||
show_logo,
|
||||
has_tags
|
||||
classObj,
|
||||
layout,
|
||||
collapsed,
|
||||
showLogo,
|
||||
showTags,
|
||||
showBreadcrumb,
|
||||
showHamburger,
|
||||
showScreenfull,
|
||||
showUserInfo,
|
||||
showNavbar,
|
||||
fixedHeader,
|
||||
// fixedNavbar,
|
||||
// fixedTags,
|
||||
setCollapsed
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(.ant-layout-header) {
|
||||
height: @topSilderHeight;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
position: fixed;
|
||||
.app__wrap {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 20;
|
||||
&--light {
|
||||
background: @menuLightBg;
|
||||
.sidebar__wrap {
|
||||
position: fixed;
|
||||
width: @menuWidth;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
transition: width 0.2s;
|
||||
}
|
||||
&--dark {
|
||||
background: @menuBg;
|
||||
.screenfull-item,
|
||||
.name-item {
|
||||
color: #fff;
|
||||
.sidebar__wrap--collapsed {
|
||||
width: @menuMinWidth;
|
||||
@{deep}(.anticon-item) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.header-silder--wrap {
|
||||
flex: 1;
|
||||
margin: 0 50px;
|
||||
height: 100% !important;
|
||||
.ant-menu-horizontal {
|
||||
height: @topSilderHeight;
|
||||
line-height: @topSilderHeight;
|
||||
border-bottom: 0;
|
||||
.main__wrap {
|
||||
position: absolute;
|
||||
width: calc(~"100% - @{menuWidth}");
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: @menuWidth;
|
||||
transition: all 0.2s;
|
||||
z-index: 1;
|
||||
.header__wrap {
|
||||
transition: all 0.2s;
|
||||
.navbar__wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @navbarHeight;
|
||||
padding: 0 20px 0 15px;
|
||||
position: relative;
|
||||
background: @contentBg;
|
||||
&:after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-top: 1px solid #d8dce5;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
@{deep}(.hover-container) {
|
||||
transition: background 0.2s;
|
||||
height: 100%;
|
||||
line-height: @navbarHeight + 5px;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
.navbar__wrap--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @navbarHeight;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 20px;
|
||||
@{deep}(.screenfull-container),
|
||||
@{deep}(.user-container) {
|
||||
line-height: @navbarHeight !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-menu-light {
|
||||
height: calc(~"@{topSilderHeight} - 4px");
|
||||
line-height: calc(~"@{topSilderHeight} - 4px");
|
||||
|
||||
// content样式
|
||||
.main__wrap--content {
|
||||
height: 100%;
|
||||
@{deep}(.el-scrollbar__wrap) {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
}
|
||||
// content样式
|
||||
}
|
||||
.right-menu {
|
||||
.main__wrap--collapsed {
|
||||
width: calc(~"100% - @{menuMinWidth}");
|
||||
left: @menuMinWidth;
|
||||
}
|
||||
}
|
||||
|
||||
// 顶部模式
|
||||
.app__wrap--Top {
|
||||
.sidebar__wrap--Top {
|
||||
height: @topSiderHeight;
|
||||
display: flex;
|
||||
.screenfull-item {
|
||||
line-height: @topSilderHeight;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: 0 20px;
|
||||
background-color: @topMenuBg;
|
||||
position: relative;
|
||||
&:after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
border-top: 1px solid #d8dce5;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
.avatar-container {
|
||||
margin-right: 0;
|
||||
.sidebar__item--Top {
|
||||
flex: 1;
|
||||
margin: 0 50px;
|
||||
}
|
||||
.navbar__wrap--right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: @topSiderHeight;
|
||||
@{deep}(.hover-container) {
|
||||
transition: background 0.2s;
|
||||
height: 100%;
|
||||
line-height: @topSiderHeight;
|
||||
padding: 0 5px;
|
||||
text-align: center;
|
||||
&:hover {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-layout-content {
|
||||
margin-top: @topSilderHeight;
|
||||
height: calc(~"100vh - @{topSilderHeight}");
|
||||
.main-wrap {
|
||||
background-color: @contentBg;
|
||||
.header__wrap--fixed {
|
||||
position: fixed !important;
|
||||
width: 100% !important;
|
||||
top: @topSiderHeight !important;
|
||||
left: 0 !important;
|
||||
z-index: 200;
|
||||
}
|
||||
.main__wrap {
|
||||
width: 100%;
|
||||
left: 0;
|
||||
height: calc(~"100% - @{topSiderHeight}");
|
||||
top: @topSiderHeight;
|
||||
}
|
||||
.main__wrap--fixed--all,
|
||||
.main__wrap--fixed--tags {
|
||||
margin-top: @navbarHeight !important;
|
||||
height: calc(~"100% - @{navbarHeight}") !important;
|
||||
}
|
||||
}
|
||||
.layout-content-has-tags {
|
||||
margin-top: @topSilderHeight + @tagsViewHeight;
|
||||
height: calc(~"100vh - @{topSilderHeight} - @{tagsViewHeight}");
|
||||
}
|
||||
.has-tags {
|
||||
position: fixed;
|
||||
top: @topSilderHeight;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 20;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -47,7 +47,7 @@ setupSvgIcon(app) // 全局注册svgIcon组件
|
||||
|
||||
setupGlobCom(app) // 注册全局公用组件
|
||||
|
||||
// setupDirectives(app) // 注册全局自定义指令
|
||||
setupDirectives(app) // 注册全局自定义指令
|
||||
|
||||
// mockXHR() // mock注册
|
||||
|
||||
|
||||
@@ -4,9 +4,7 @@ import NProgress from 'nprogress' // 引入进度条
|
||||
|
||||
import 'nprogress/nprogress.css' // 进度条样式
|
||||
|
||||
import config from './config'
|
||||
|
||||
const { user_info, title } = config
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
|
||||
import wsCache from '@/cache'
|
||||
|
||||
@@ -20,7 +18,7 @@ import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
const whiteList: string[] = ['/login'] // 不重定向白名单
|
||||
router.beforeEach((to, from, next) => {
|
||||
if (wsCache.get(user_info)) {
|
||||
if (wsCache.get(appStore.userInfo)) {
|
||||
if (to.path === '/login') {
|
||||
next({ path: '/' })
|
||||
} else {
|
||||
@@ -55,6 +53,6 @@ router.beforeEach((to, from, next) => {
|
||||
})
|
||||
|
||||
router.afterEach((to) => {
|
||||
document.title = getPageTitle(to.meta.title, title)
|
||||
document.title = getPageTitle(to.meta.title, appStore.title)
|
||||
NProgress.done() // 结束进度条
|
||||
})
|
||||
|
||||
@@ -6,8 +6,6 @@ import { getParentLayout } from './utils'
|
||||
|
||||
/* Layout */
|
||||
const Layout = () => import('../layout/index.vue')
|
||||
/* ParentView */
|
||||
import ParentView from '_c/ParentView/index.vue'
|
||||
|
||||
/**
|
||||
* redirect: noredirect 当设置 noredirect 的时候该路由在面包屑导航中不可被点击
|
||||
@@ -50,7 +48,8 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
|
||||
name: 'NoFind',
|
||||
meta: {
|
||||
hidden: true,
|
||||
title: '404'
|
||||
title: '404',
|
||||
noTagsView: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -83,281 +82,305 @@ export const constantRouterMap: AppRouteRecordRaw[] = [
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// path: '/external-link',
|
||||
// component: Layout,
|
||||
// meta: {},
|
||||
// children: [
|
||||
// {
|
||||
// path: 'http://192.168.169.57/ue/2019/doc/vue-standard/dist/',
|
||||
// meta: { title: '文档', icon: 'documentation' }
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
{
|
||||
path: '/external-link',
|
||||
component: Layout,
|
||||
meta: {},
|
||||
children: [
|
||||
{
|
||||
path: 'http://192.168.169.57/ue/2019/doc/vue-standard/dist/',
|
||||
meta: { title: '文档', icon: 'documentation' }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export const asyncRouterMap: AppRouteRecordRaw[] = [
|
||||
// {
|
||||
// path: '/components-demo',
|
||||
// component: Layout,
|
||||
// redirect: '/components-demo/echarts',
|
||||
// name: 'ComponentsDemo',
|
||||
// meta: {
|
||||
// title: '功能组件',
|
||||
// icon: 'component',
|
||||
// alwaysShow: true
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: 'echarts',
|
||||
// component: () => import('_p/index/views/components-demo/echarts/index.vue'),
|
||||
// name: 'EchartsDemo',
|
||||
// meta: {
|
||||
// title: '图表'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'image',
|
||||
// component: () => import('_p/index/views/components-demo/image/index.vue'),
|
||||
// name: 'ImageDemo',
|
||||
// meta: {
|
||||
// title: '图片'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'preview',
|
||||
// component: () => import('_p/index/views/components-demo/preview/index.vue'),
|
||||
// name: 'PreviewDemo',
|
||||
// meta: {
|
||||
// title: '图片预览'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'scroll',
|
||||
// component: () => import('_p/index/views/components-demo/scroll/index.vue'),
|
||||
// name: 'ScrollDemo',
|
||||
// meta: {
|
||||
// title: '滚动'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'count-to',
|
||||
// component: () => import('_p/index/views/components-demo/count-to/index.vue'),
|
||||
// name: 'CountToDemo',
|
||||
// meta: {
|
||||
// title: '数字动画'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'search',
|
||||
// component: () => import('_p/index/views/components-demo/search/index.vue'),
|
||||
// name: 'SearchDemo',
|
||||
// meta: {
|
||||
// title: '查询'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'button',
|
||||
// component: () => import('_p/index/views/components-demo/button/index.vue'),
|
||||
// name: 'ButtonDemo',
|
||||
// meta: {
|
||||
// title: '按钮'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'editor',
|
||||
// component: () => import('_p/index/views/components-demo/editor/index.vue'),
|
||||
// name: 'EditorDemo',
|
||||
// meta: {
|
||||
// title: '富文本编辑器'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'markdown',
|
||||
// component: () => import('_p/index/views/components-demo/markdown/index.vue'),
|
||||
// name: 'MarkdownDemo',
|
||||
// meta: {
|
||||
// title: 'markdown编辑器'
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// // {
|
||||
// // path: '/table-demo',
|
||||
// // component: Layout,
|
||||
// // redirect: '/table-demo/basic-usage',
|
||||
// // name: 'TableDemo',
|
||||
// // meta: {
|
||||
// // title: '表格',
|
||||
// // icon: 'table',
|
||||
// // alwaysShow: true
|
||||
// // },
|
||||
// // children: [
|
||||
// // // {
|
||||
// // // path: 'test',
|
||||
// // // component: () => import('_p/index/views/table-demo/test'),
|
||||
// // // name: 'test',
|
||||
// // // meta: {
|
||||
// // // title: 'test'
|
||||
// // // }
|
||||
// // // },
|
||||
// // {
|
||||
// // path: 'basic-usage',
|
||||
// // component: () => import('_p/index/views/table-demo/basic-usage/index.vue'),
|
||||
// // name: 'BasicUsage',
|
||||
// // meta: {
|
||||
// // title: '基础用法'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'table-ellipsis',
|
||||
// // component: () => import('_p/index/views/table-demo/table-ellipsis/index.vue'),
|
||||
// // name: 'TableEllipsis',
|
||||
// // meta: {
|
||||
// // title: '单元格自动省略'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'table-load',
|
||||
// // component: () => import('_p/index/views/table-demo/table-load/index.vue'),
|
||||
// // name: 'TableLoad',
|
||||
// // meta: {
|
||||
// // title: '远程加载数据'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'table-border',
|
||||
// // component: () => import('_p/index/views/table-demo/table-border/index.vue'),
|
||||
// // name: 'TableBorder',
|
||||
// // meta: {
|
||||
// // title: '带边框'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'table-merge',
|
||||
// // component: () => import('_p/index/views/table-demo/table-merge/index.vue'),
|
||||
// // name: 'TableMerge',
|
||||
// // meta: {
|
||||
// // title: '表格行/列合并'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'custom-menu',
|
||||
// // component: () => import('_p/index/views/table-demo/custom-menu/index.vue'),
|
||||
// // name: 'CustomMenu',
|
||||
// // meta: {
|
||||
// // title: '自定义筛选菜单'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'edit-cell',
|
||||
// // component: () => import('_p/index/views/table-demo/edit-cell/index.vue'),
|
||||
// // name: 'EditCell',
|
||||
// // meta: {
|
||||
// // title: '可编辑单元格'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'edit-row',
|
||||
// // component: () => import('_p/index/views/table-demo/edit-row/index.vue'),
|
||||
// // name: 'EditRow',
|
||||
// // meta: {
|
||||
// // title: '可编辑行'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'table-tree',
|
||||
// // component: () => import('_p/index/views/table-demo/table-tree/index.vue'),
|
||||
// // name: 'TableTree',
|
||||
// // meta: {
|
||||
// // title: '树形数据展示'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'table-expanded',
|
||||
// // component: () => import('_p/index/views/table-demo/table-expanded/index.vue'),
|
||||
// // name: 'TableExpanded',
|
||||
// // meta: {
|
||||
// // title: '可展开'
|
||||
// // }
|
||||
// // },
|
||||
// // {
|
||||
// // path: 'fixed-header',
|
||||
// // component: () => import('_p/index/views/table-demo/fixed-header/index.vue'),
|
||||
// // name: 'FixedHeader',
|
||||
// // meta: {
|
||||
// // title: '固定头和列'
|
||||
// // }
|
||||
// // }
|
||||
// // ]
|
||||
// // },
|
||||
// {
|
||||
// path: '/directives-demo',
|
||||
// component: Layout,
|
||||
// redirect: '/directives-demo/clipboard',
|
||||
// name: 'DirectivesDemo',
|
||||
// meta: {
|
||||
// title: '自定义指令',
|
||||
// icon: 'clipboard',
|
||||
// alwaysShow: true
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: 'clipboard',
|
||||
// component: () => import('_p/index/views/directives-demo/clipboard/index.vue'),
|
||||
// name: 'ClipboardDemo',
|
||||
// meta: {
|
||||
// title: 'Clipboard'
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/hooks-demo',
|
||||
// component: Layout,
|
||||
// redirect: '/hooks-demo/watermark',
|
||||
// name: 'HooksDemo',
|
||||
// meta: {
|
||||
// title: 'Hooks',
|
||||
// icon: 'international',
|
||||
// alwaysShow: true
|
||||
// },
|
||||
// children: [
|
||||
// {
|
||||
// path: 'watermark',
|
||||
// component: () => import('_p/index/views/hooks-demo/useWatermark/index.vue'),
|
||||
// name: 'UseWatermarkDemo',
|
||||
// meta: {
|
||||
// title: 'UseWaterMark'
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// path: 'useScrollTo',
|
||||
// component: () => import('_p/index/views/hooks-demo/useScrollTo/index.vue'),
|
||||
// name: 'UseScrollToDemo',
|
||||
// meta: {
|
||||
// title: 'UseScrollTo'
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// path: '/icon',
|
||||
// component: Layout,
|
||||
// name: 'IconsDemo',
|
||||
// meta: {},
|
||||
// children: [
|
||||
// {
|
||||
// path: 'index',
|
||||
// component: () => import('_p/index/views/icons/index.vue'),
|
||||
// name: 'Icons',
|
||||
// meta: {
|
||||
// title: '图标',
|
||||
// icon: 'icon'
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
path: '/components-demo',
|
||||
component: Layout,
|
||||
redirect: '/components-demo/echarts',
|
||||
name: 'ComponentsDemo',
|
||||
meta: {
|
||||
title: '功能组件',
|
||||
icon: 'component',
|
||||
alwaysShow: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'echarts',
|
||||
component: () => import('_p/index/views/components-demo/echarts/index.vue'),
|
||||
name: 'EchartsDemo',
|
||||
meta: {
|
||||
title: '图表'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'preview',
|
||||
component: () => import('_p/index/views/components-demo/preview/index.vue'),
|
||||
name: 'PreviewDemo',
|
||||
meta: {
|
||||
title: '图片预览'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'count-to',
|
||||
component: () => import('_p/index/views/components-demo/count-to/index.vue'),
|
||||
name: 'CountToDemo',
|
||||
meta: {
|
||||
title: '数字动画'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'search',
|
||||
component: () => import('_p/index/views/components-demo/search/index.vue'),
|
||||
name: 'SearchDemo',
|
||||
meta: {
|
||||
title: '查询'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'editor',
|
||||
component: () => import('_p/index/views/components-demo/editor/index.vue'),
|
||||
name: 'EditorDemo',
|
||||
meta: {
|
||||
title: '富文本编辑器'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'markdown',
|
||||
component: () => import('_p/index/views/components-demo/markdown/index.vue'),
|
||||
name: 'MarkdownDemo',
|
||||
meta: {
|
||||
title: 'markdown编辑器'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/table-demo',
|
||||
component: Layout,
|
||||
redirect: '/table-demo/basic-usage',
|
||||
name: 'TableDemo',
|
||||
meta: {
|
||||
title: '表格',
|
||||
icon: 'table',
|
||||
alwaysShow: true
|
||||
},
|
||||
children: [
|
||||
// {
|
||||
// path: 'test',
|
||||
// component: () => import('_p/index/views/table-demo/test'),
|
||||
// name: 'test',
|
||||
// meta: {
|
||||
// title: 'test'
|
||||
// }
|
||||
// },
|
||||
{
|
||||
path: 'basic-table',
|
||||
component: () => import('_p/index/views/table-demo/basic-table/index.vue'),
|
||||
name: 'BasicTable',
|
||||
meta: {
|
||||
title: '基础表格'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'stripe-table',
|
||||
component: () => import('_p/index/views/table-demo/stripe-table/index.vue'),
|
||||
name: 'StripeTable',
|
||||
meta: {
|
||||
title: '带斑马纹表格'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'border-table',
|
||||
component: () => import('_p/index/views/table-demo/border-table/index.vue'),
|
||||
name: 'BorderTable',
|
||||
meta: {
|
||||
title: '带边框表格'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'state-table',
|
||||
component: () => import('_p/index/views/table-demo/state-table/index.vue'),
|
||||
name: 'StateTable',
|
||||
meta: {
|
||||
title: '带状态表格'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'fixed-header',
|
||||
component: () => import('_p/index/views/table-demo/fixed-header/index.vue'),
|
||||
name: 'FixedHeader',
|
||||
meta: {
|
||||
title: '固定表头'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'fixed-column',
|
||||
component: () => import('_p/index/views/table-demo/fixed-column/index.vue'),
|
||||
name: 'FixedColumn',
|
||||
meta: {
|
||||
title: '固定列'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'fixed-column-header',
|
||||
component: () => import('_p/index/views/table-demo/fixed-column-header/index.vue'),
|
||||
name: 'FixedColumnHeader',
|
||||
meta: {
|
||||
title: '固定列和表头'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'fluid-height',
|
||||
component: () => import('_p/index/views/table-demo/fluid-height/index.vue'),
|
||||
name: 'FluidHeight',
|
||||
meta: {
|
||||
title: '流体高度'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'multi-header',
|
||||
component: () => import('_p/index/views/table-demo/multi-header/index.vue'),
|
||||
name: 'MultiHeader',
|
||||
meta: {
|
||||
title: '多级表头'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'single-choice',
|
||||
component: () => import('_p/index/views/table-demo/single-choice/index.vue'),
|
||||
name: 'SingleChoice',
|
||||
meta: {
|
||||
title: '单选'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'multiple-choice',
|
||||
component: () => import('_p/index/views/table-demo/multiple-choice/index.vue'),
|
||||
name: 'MultipleChoice',
|
||||
meta: {
|
||||
title: '多选'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'sort-table',
|
||||
component: () => import('_p/index/views/table-demo/sort-table/index.vue'),
|
||||
name: 'SortTable',
|
||||
meta: {
|
||||
title: '排序'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'screen-table',
|
||||
component: () => import('_p/index/views/table-demo/screen-table/index.vue'),
|
||||
name: 'ScreenTable',
|
||||
meta: {
|
||||
title: '筛选'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'expand-row',
|
||||
component: () => import('_p/index/views/table-demo/expand-row/index.vue'),
|
||||
name: 'ExpandRow',
|
||||
meta: {
|
||||
title: '展开行'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'tree-and-load',
|
||||
component: () => import('_p/index/views/table-demo/tree-and-load/index.vue'),
|
||||
name: 'TreeAndLoad',
|
||||
meta: {
|
||||
title: '树形数据与懒加载'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'custom-header',
|
||||
component: () => import('_p/index/views/table-demo/custom-header/index.vue'),
|
||||
name: 'CustomHeader',
|
||||
meta: {
|
||||
title: '自定义表头'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'total-table',
|
||||
component: () => import('_p/index/views/table-demo/total-table/index.vue'),
|
||||
name: 'TotalTable',
|
||||
meta: {
|
||||
title: '表尾合计行'
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/directives-demo',
|
||||
component: Layout,
|
||||
redirect: '/directives-demo/clipboard',
|
||||
name: 'DirectivesDemo',
|
||||
meta: {
|
||||
title: '自定义指令',
|
||||
icon: 'clipboard',
|
||||
alwaysShow: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'clipboard',
|
||||
component: () => import('_p/index/views/directives-demo/clipboard/index.vue'),
|
||||
name: 'ClipboardDemo',
|
||||
meta: {
|
||||
title: 'Clipboard'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/hooks-demo',
|
||||
component: Layout,
|
||||
redirect: '/hooks-demo/watermark',
|
||||
name: 'HooksDemo',
|
||||
meta: {
|
||||
title: 'Hooks',
|
||||
icon: 'international',
|
||||
alwaysShow: true
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'watermark',
|
||||
component: () => import('_p/index/views/hooks-demo/useWatermark/index.vue'),
|
||||
name: 'UseWatermarkDemo',
|
||||
meta: {
|
||||
title: 'UseWaterMark'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'useScrollTo',
|
||||
component: () => import('_p/index/views/hooks-demo/useScrollTo/index.vue'),
|
||||
name: 'UseScrollToDemo',
|
||||
meta: {
|
||||
title: 'UseScrollTo'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/icon',
|
||||
component: Layout,
|
||||
name: 'IconsDemo',
|
||||
meta: {},
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('_p/index/views/icons/index.vue'),
|
||||
name: 'Icons',
|
||||
meta: {
|
||||
title: '图标',
|
||||
icon: 'icon'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/level',
|
||||
component: Layout,
|
||||
|
||||
@@ -15,6 +15,8 @@ export interface AppState {
|
||||
showScreenfull: Boolean
|
||||
showUserInfo: Boolean
|
||||
title: String
|
||||
logoTitle: String
|
||||
userInfo: String
|
||||
}
|
||||
|
||||
@Module({ dynamic: true, namespaced: true, store, name: 'app' })
|
||||
@@ -31,7 +33,9 @@ class App extends VuexModule implements AppState {
|
||||
public showHamburger = true // 是否显示侧边栏缩收按钮
|
||||
public showScreenfull = true // 是否全屏按钮
|
||||
public showUserInfo = true // 是否显示用户头像
|
||||
public title = 'vue-antdv-admin' // 标题
|
||||
public title = 'vue-element-plus-admin' // 标题
|
||||
public logoTitle = 'vue-ElPlus-admin' // logo标题
|
||||
public userInfo = 'userInfo' // 登录信息存储字段-建议每个项目换一个字段,避免与其他项目冲突
|
||||
|
||||
@Mutation
|
||||
private SET_COLLAPSED(collapsed: boolean): void {
|
||||
@@ -85,6 +89,10 @@ class App extends VuexModule implements AppState {
|
||||
private SET_TITLE(title: string): void {
|
||||
this.title = title
|
||||
}
|
||||
@Mutation
|
||||
private SET_LOGOTITLE(logoTitle: string): void {
|
||||
this.logoTitle = logoTitle
|
||||
}
|
||||
|
||||
@Action
|
||||
public SetCollapsed(collapsed: boolean): void {
|
||||
@@ -138,6 +146,10 @@ class App extends VuexModule implements AppState {
|
||||
public SetTitle(title: string): void {
|
||||
this.SET_TITLE(title)
|
||||
}
|
||||
@Action
|
||||
public SetLogoTitle(logoTitle: string): void {
|
||||
this.SET_LOGOTITLE(logoTitle)
|
||||
}
|
||||
}
|
||||
|
||||
export const appStore = getModule<App>(App)
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="扩展 antdv 的 Button 组件,实现 primary、success、warning、info、default 等主题样式。" style="margin-bottom: 20px;" />
|
||||
<el-alert message="扩展 antdv 的 Button 组件,实现 primary、success、warning、info、default 等主题样式。" style="margin-bottom: 20px;" />
|
||||
<div class="btn__wrap">default</div>
|
||||
<div class="btn__item">
|
||||
<a-button>默认按钮</a-button>
|
||||
<a-button shape="round">默认按钮</a-button>
|
||||
<a-button loading>默认按钮</a-button>
|
||||
<a-button disabled>默认按钮</a-button>
|
||||
<el-button>默认按钮</el-button>
|
||||
<el-button shape="round">默认按钮</el-button>
|
||||
<el-button loading>默认按钮</el-button>
|
||||
<el-button disabled>默认按钮</el-button>
|
||||
</div>
|
||||
<div class="btn__wrap">primary</div>
|
||||
<div class="btn__item">
|
||||
<a-button type="primary">主要按钮</a-button>
|
||||
<a-button type="primary" shape="round">主要按钮</a-button>
|
||||
<a-button type="primary" loading>主要按钮</a-button>
|
||||
<a-button type="primary" disabled>主要按钮</a-button>
|
||||
<el-button type="primary">主要按钮</el-button>
|
||||
<el-button type="primary" shape="round">主要按钮</el-button>
|
||||
<el-button type="primary" loading>主要按钮</el-button>
|
||||
<el-button type="primary" disabled>主要按钮</el-button>
|
||||
</div>
|
||||
<div class="btn__wrap">success</div>
|
||||
<div class="btn__item">
|
||||
<a-button type="success">成功按钮</a-button>
|
||||
<a-button type="success" shape="round">成功按钮</a-button>
|
||||
<a-button type="success" loading>成功按钮</a-button>
|
||||
<a-button type="success" disabled>成功按钮</a-button>
|
||||
<el-button type="success">成功按钮</el-button>
|
||||
<el-button type="success" shape="round">成功按钮</el-button>
|
||||
<el-button type="success" loading>成功按钮</el-button>
|
||||
<el-button type="success" disabled>成功按钮</el-button>
|
||||
</div>
|
||||
<div class="btn__wrap">warning</div>
|
||||
<div class="btn__item">
|
||||
<a-button type="warning">警告按钮</a-button>
|
||||
<a-button type="warning" shape="round">警告按钮</a-button>
|
||||
<a-button type="warning" loading>警告按钮</a-button>
|
||||
<a-button type="warning" disabled>警告按钮</a-button>
|
||||
<el-button type="warning">警告按钮</el-button>
|
||||
<el-button type="warning" shape="round">警告按钮</el-button>
|
||||
<el-button type="warning" loading>警告按钮</el-button>
|
||||
<el-button type="warning" disabled>警告按钮</el-button>
|
||||
</div>
|
||||
<div class="btn__wrap">danger</div>
|
||||
<div class="btn__item">
|
||||
<a-button type="danger">危险按钮</a-button>
|
||||
<a-button type="danger" shape="round">危险按钮</a-button>
|
||||
<a-button type="danger" loading>危险按钮</a-button>
|
||||
<a-button type="danger" disabled>危险按钮</a-button>
|
||||
<el-button type="danger">危险按钮</el-button>
|
||||
<el-button type="danger" shape="round">危险按钮</el-button>
|
||||
<el-button type="danger" loading>危险按钮</el-button>
|
||||
<el-button type="danger" disabled>危险按钮</el-button>
|
||||
</div>
|
||||
<div class="btn__wrap">info</div>
|
||||
<div class="btn__item">
|
||||
<a-button type="info">信息按钮</a-button>
|
||||
<a-button type="info" shape="round">信息按钮</a-button>
|
||||
<a-button type="info" loading>信息按钮</a-button>
|
||||
<a-button type="info" disabled>信息按钮</a-button>
|
||||
<el-button type="info">信息按钮</el-button>
|
||||
<el-button type="info" shape="round">信息按钮</el-button>
|
||||
<el-button type="info" loading>信息按钮</el-button>
|
||||
<el-button type="info" disabled>信息按钮</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="基于 vue-count-to 进行改造,支持所有 vue-count-to 参数。" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 vue-count-to 进行改造,支持所有 vue-count-to 参数。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
|
||||
<div class="count-to">
|
||||
<count-to
|
||||
@@ -17,44 +23,44 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="action">
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="8">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<div class="action__item">
|
||||
<span>startVal:</span><a-input-number v-model:value="startVal" :min="0" />
|
||||
<span>startVal:</span><el-input-number v-model="startVal" :min="0" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="action__item">
|
||||
<span>endVal:</span><a-input-number v-model:value="endVal" :min="1" />
|
||||
<span>endVal:</span><el-input-number v-model="endVal" :min="1" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="action__item">
|
||||
<span>duration:</span><a-input-number v-model:value="duration" :min="1000" />
|
||||
<span>duration:</span><el-input-number v-model="duration" :min="1000" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="action__item">
|
||||
<span>separator:</span><a-input v-model:value="separator" />
|
||||
<span>separator:</span><el-input v-model="separator" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="action__item">
|
||||
<span>prefix:</span><a-input v-model:value="prefix" />
|
||||
<span>prefix:</span><el-input v-model="prefix" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="8">
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="action__item">
|
||||
<span>suffix:</span><a-input v-model:value="suffix" />
|
||||
<span>suffix:</span><el-input v-model="suffix" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<div style="text-align: center;margin-top: 20px;">
|
||||
<a-button type="primary" @click="start">start</a-button>
|
||||
<a-button style="margin-left: 10px;" @click="pauseResume">pause/resume</a-button>
|
||||
<el-button type="primary" @click="start">start</el-button>
|
||||
<el-button style="margin-left: 10px;" @click="pauseResume">pause/resume</el-button>
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -121,10 +127,11 @@ export default defineComponent({
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
&>span {
|
||||
width: 100px;
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
@{deep}(.ant-input-number) {
|
||||
@{deep}(.el-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="统一封装 Echart 组件,自适应宽度,只需传入 options 与 height 属性即可展示对应的图表。" type="info" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="统一封装 Echart 组件,自适应宽度,只需传入 options 与 height 属性即可展示对应的图表。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
|
||||
<a-row :gutter="20">
|
||||
<a-col :span="10">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<div class="chart-wrap">
|
||||
<echart :options="pieOptions" :height="'300px'" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="chart-wrap">
|
||||
<echart :options="barOptions" :height="'300px'" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="chart-wrap">
|
||||
<echart :options="lineOptions" :height="'300px'" />
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :span="10">
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<div class="chart-wrap">
|
||||
<echart :options="pieOptions2" :height="'300px'" />
|
||||
</div>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="基于 wangeditor 封装的 富文本 组件。" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 wangeditor 封装的 富文本 组件。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<editor v-model:value="html" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="抽取于 Element 的 Image 组件进行改造,在保留原生img的特性下,支持懒加载,自定义占位、加载失败等。" style="margin-bottom: 20px;" />
|
||||
<div class="demo-image">
|
||||
<div v-for="fit in fits" :key="fit" class="block">
|
||||
<span class="demonstration">{{ fit }}</span>
|
||||
<c-image
|
||||
:src="url"
|
||||
:fit="fit"
|
||||
style="width: 100px; height: 100px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-alert message="占位内容" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<div class="demo-image__placeholder">
|
||||
<div class="block">
|
||||
<span class="demonstration">默认</span>
|
||||
<c-image :src="src" style="width: 300px; height: 200px" />
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">自定义</span>
|
||||
<c-image :src="src" style="width: 300px; height: 200px">
|
||||
<template #placeholder>
|
||||
<div class="image-slot">
|
||||
加载中...
|
||||
</div>
|
||||
</template>
|
||||
</c-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-alert message="加载失败" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<div class="demo-image__error">
|
||||
<div class="block">
|
||||
<span class="demonstration">默认</span>
|
||||
<c-image style="width: 300px; height: 200px" />
|
||||
</div>
|
||||
<div class="block">
|
||||
<span class="demonstration">自定义</span>
|
||||
<c-image style="width: 300px; height: 200px">
|
||||
<template #error>
|
||||
<div class="image-slot">
|
||||
<PictureOutlined />
|
||||
</div>
|
||||
</template>
|
||||
</c-image>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-alert message="懒加载" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<div class="demo-image__lazy">
|
||||
<c-image
|
||||
v-for="url in urls"
|
||||
:key="url"
|
||||
:src="url"
|
||||
lazy
|
||||
style="display: block;min-height: 200px;margin-bottom: 10px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import CImage from '_c/Image/index.vue'
|
||||
import { PictureOutlined } from '@ant-design/icons-vue'
|
||||
export default defineComponent({
|
||||
// name: 'Image',
|
||||
components: {
|
||||
CImage,
|
||||
PictureOutlined
|
||||
},
|
||||
setup() {
|
||||
const fits = ref<string[]>(['fill', 'contain', 'cover', 'none', 'scale-down'])
|
||||
const url = ref<string>('https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg')
|
||||
const src = ref<string>('https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg')
|
||||
const urls = ref<string[]>([
|
||||
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
|
||||
'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg'
|
||||
])
|
||||
return {
|
||||
fits,
|
||||
url,
|
||||
src,
|
||||
urls
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.demo-image,
|
||||
.demo-image__placeholder,
|
||||
.demo-image__error {
|
||||
background: #fff;
|
||||
}
|
||||
.demo-image .block,
|
||||
.demo-image__error .block,
|
||||
.demo-image__placeholder .block {
|
||||
padding: 30px 0;
|
||||
text-align: center;
|
||||
border-right: 1px solid #eff2f6;
|
||||
display: inline-block;
|
||||
width: 20%;
|
||||
box-sizing: border-box;
|
||||
vertical-align: top;
|
||||
.demonstration {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.image__error,
|
||||
.image-slot {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #c0c4cc;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
height: 100%;
|
||||
background: #f5f7fa;
|
||||
}
|
||||
}
|
||||
.demo-image__error .block,
|
||||
.demo-image__placeholder .block {
|
||||
text-align: center;
|
||||
width: 49%;
|
||||
}
|
||||
|
||||
.demo-image__lazy {
|
||||
width: 800px;
|
||||
height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,12 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="基于 vditor 封装的 Markdown编辑器 组件。" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 vditor 封装的 Markdown编辑器 组件。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<markdown v-model:value="html" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="抽取于 Element 的图片预览组件进行改造,实现函数式调用组件,无需基于图片进行点击预览。" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="抽取于 Element 的图片预览组件进行改造,实现函数式调用组件,无需基于图片进行点击预览。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
|
||||
<a-alert message="有底图预览" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="有底图预览。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<div class="img-wrap">
|
||||
<div
|
||||
v-for="(item, $index) in imgList"
|
||||
@@ -14,18 +26,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-alert message="无底图预览" style="margin-bottom: 20px; margin-top: 20px;" />
|
||||
<a-button type="primary" @click="showNoImg">点击预览</a-button>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="无底图预览。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px; margin-top: 20px;"
|
||||
/>
|
||||
<el-button type="primary" @click="showNoImg">点击预览</el-button>
|
||||
|
||||
<a-alert message="点击事件,包含图片点击事件以及关闭事件。" style="margin-bottom: 20px; margin-top: 20px;" />
|
||||
<a-button type="primary" @click="showImg">点击预览</a-button>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="点击事件,包含图片点击事件以及关闭事件。。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px; margin-top: 20px;"
|
||||
/>
|
||||
<el-button type="primary" @click="showImg">点击预览</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { createImgPreview } from '_c/Preview/functional'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
export default defineComponent({
|
||||
// name: 'PreviewDemo',
|
||||
setup() {
|
||||
@@ -59,10 +83,10 @@ export default defineComponent({
|
||||
show: true,
|
||||
index: 0,
|
||||
onSelect: (i: number) => {
|
||||
message.info('当前点击的图片索引:' + i)
|
||||
ElMessage.info('当前点击的图片索引:' + i)
|
||||
},
|
||||
onClose: (i: number) => {
|
||||
message.info('关闭之后的图片索引:' + i)
|
||||
ElMessage.info('关闭之后的图片索引:' + i)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="抽取于 Element 的 Scrollbar 组件进行改造统一美化各个浏览器滚动条,保持一致性。" style="margin-bottom: 20px;" />
|
||||
<el-alert message="抽取于 Element 的 Scrollbar 组件进行改造统一美化各个浏览器滚动条,保持一致性。" style="margin-bottom: 20px;" />
|
||||
|
||||
<a-alert message="横向滚动,外围容器需要设置固定宽度。" style="margin-bottom: 20px;" />
|
||||
<el-alert message="横向滚动,外围容器需要设置固定宽度。" style="margin-bottom: 20px;" />
|
||||
<div class="deom__wrap deom__wrap--horizontal">
|
||||
<scrollbar>
|
||||
<ul class="deom-ul__wrap">
|
||||
@@ -11,7 +11,7 @@
|
||||
</scrollbar>
|
||||
</div>
|
||||
|
||||
<a-alert message="纵向滚动,外围容器需要设置固定高度。" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<el-alert message="纵向滚动,外围容器需要设置固定高度。" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<div class="deom__wrap deom__wrap--vertical">
|
||||
<scrollbar>
|
||||
<ul class="deom-ul__wrap">
|
||||
|
||||
@@ -2,16 +2,16 @@ export const classicData = [
|
||||
{
|
||||
label: '即时配送',
|
||||
value: true,
|
||||
type: 'switch',
|
||||
itemType: 'switch',
|
||||
field: 'delivery'
|
||||
},
|
||||
{
|
||||
label: '活动名称',
|
||||
value: '',
|
||||
type: 'input',
|
||||
placeholder: '活动名称',
|
||||
itemType: 'input',
|
||||
field: 'name',
|
||||
allowClear: true,
|
||||
placeholder: '活动名称',
|
||||
clearable: true,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
@@ -21,11 +21,11 @@ export const classicData = [
|
||||
},
|
||||
{
|
||||
label: '活动区域',
|
||||
value: undefined,
|
||||
type: 'select',
|
||||
value: '',
|
||||
itemType: 'select',
|
||||
placeholder: '活动区域',
|
||||
clearable: true,
|
||||
field: 'region',
|
||||
allowClear: true,
|
||||
options: [
|
||||
{
|
||||
title: '区域一',
|
||||
@@ -38,7 +38,7 @@ export const classicData = [
|
||||
],
|
||||
rules: [
|
||||
{
|
||||
type: 'string',
|
||||
itemType: 'string',
|
||||
required: true,
|
||||
message: '请选择活动区域'
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export const classicData = [
|
||||
{
|
||||
label: '特殊资源',
|
||||
value: '2',
|
||||
type: 'radio',
|
||||
itemType: 'radio',
|
||||
field: 'resource',
|
||||
radioType: 'button', // button or radio
|
||||
options: [
|
||||
@@ -61,87 +61,89 @@ export const classicData = [
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '组织机构',
|
||||
value: [],
|
||||
type: 'treeSelect',
|
||||
field: 'company',
|
||||
allowClear: true,
|
||||
placeholder: '请选择组织机构',
|
||||
treeCheckable: false,
|
||||
maxTagCount: 2,
|
||||
options: [
|
||||
{
|
||||
title: 'Node1',
|
||||
value: '0-0',
|
||||
key: '0-0',
|
||||
children: [
|
||||
{
|
||||
title: 'Child Node1',
|
||||
value: '0-0-0',
|
||||
key: '0-0-0'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Node2',
|
||||
value: '0-1',
|
||||
key: '0-1',
|
||||
children: [
|
||||
{
|
||||
title: 'Child Node3',
|
||||
value: '0-1-0',
|
||||
key: '0-1-0',
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
title: 'Child Node4',
|
||||
value: '0-1-1',
|
||||
key: '0-1-1'
|
||||
},
|
||||
{
|
||||
title: 'Child Node5',
|
||||
value: '0-1-2',
|
||||
key: '0-1-2'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
// {
|
||||
// label: '组织机构',
|
||||
// value: [],
|
||||
// itemType: 'treeSelect',
|
||||
// field: 'company',
|
||||
// allowClear: true,
|
||||
// placeholder: '请选择组织机构',
|
||||
// treeCheckable: false,
|
||||
// maxTagCount: 2,
|
||||
// options: [
|
||||
// {
|
||||
// title: 'Node1',
|
||||
// value: '0-0',
|
||||
// key: '0-0',
|
||||
// children: [
|
||||
// {
|
||||
// title: 'Child Node1',
|
||||
// value: '0-0-0',
|
||||
// key: '0-0-0'
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// title: 'Node2',
|
||||
// value: '0-1',
|
||||
// key: '0-1',
|
||||
// children: [
|
||||
// {
|
||||
// title: 'Child Node3',
|
||||
// value: '0-1-0',
|
||||
// key: '0-1-0',
|
||||
// disabled: true
|
||||
// },
|
||||
// {
|
||||
// title: 'Child Node4',
|
||||
// value: '0-1-1',
|
||||
// key: '0-1-1'
|
||||
// },
|
||||
// {
|
||||
// title: 'Child Node5',
|
||||
// value: '0-1-2',
|
||||
// key: '0-1-2'
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
label: '日选择器',
|
||||
value: null,
|
||||
type: 'datePicker',
|
||||
value: '',
|
||||
itemType: 'datePicker',
|
||||
field: 'date1',
|
||||
allowClear: true,
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
clearable: true,
|
||||
format: 'YYYY-MM-DD',
|
||||
placeholder: '请选择日期'
|
||||
},
|
||||
{
|
||||
label: '月选择器',
|
||||
value: null,
|
||||
type: 'monthPicker',
|
||||
value: '',
|
||||
itemType: 'datePicker',
|
||||
field: 'date2',
|
||||
valueFormat: 'YYYY-MM',
|
||||
allowClear: true,
|
||||
clearable: true,
|
||||
format: 'YYYY-MM',
|
||||
placeholder: '请选择日期'
|
||||
},
|
||||
{
|
||||
label: '范围选择器',
|
||||
value: null,
|
||||
type: 'rangePicker',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
value: [],
|
||||
itemType: 'datePicker',
|
||||
field: 'date3',
|
||||
allowClear: true,
|
||||
placeholder: ['请选择日期', '请选择日期']
|
||||
clearable: true,
|
||||
type: 'daterange',
|
||||
rangeSeparator: '至',
|
||||
startPlaceholder: '开始日期',
|
||||
endPlaceholder: '结束日期'
|
||||
},
|
||||
{
|
||||
label: '周选择器',
|
||||
value: null,
|
||||
type: 'weekPicker',
|
||||
value: '',
|
||||
itemType: 'datePicker',
|
||||
field: 'date4',
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
allowClear: true,
|
||||
type: 'week',
|
||||
clearable: true,
|
||||
placeholder: '请选择日期'
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="封装 antdv 的 Form 组件,实现查询、重置等功能,并提供了三种布局风格。" style="margin-bottom: 20px;" />
|
||||
<a-alert message="经典风格" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="封装 Element 的 Form 组件,实现查询、重置等功能,并提供了三种布局风格。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="经典风格。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;margin-top: 20px;"
|
||||
/>
|
||||
<div class="searh">
|
||||
<search
|
||||
:data="classicData"
|
||||
@@ -13,7 +25,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-alert message="底部操作按钮风格" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="底部操作按钮风格。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;margin-top: 20px;"
|
||||
/>
|
||||
<div class="searh">
|
||||
<search
|
||||
layout="bottom"
|
||||
@@ -26,7 +44,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-alert message="右侧操作按钮风格" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="右侧操作按钮风格。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;margin-top: 20px;"
|
||||
/>
|
||||
<div class="searh">
|
||||
<search
|
||||
layout="right"
|
||||
|
||||
@@ -16,70 +16,6 @@
|
||||
<div class="chart__wrap">
|
||||
<echart :options="lineEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
<panel-group />
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="pieEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="barEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="chart__wrap">
|
||||
<echart :options="lineEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
<panel-group />
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="pieEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="barEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="chart__wrap">
|
||||
<echart :options="lineEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
<panel-group />
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="pieEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="barEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="chart__wrap">
|
||||
<echart :options="lineEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
<panel-group />
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="pieEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<div class="chart__wrap">
|
||||
<echart :options="barEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="chart__wrap">
|
||||
<echart :options="lineEchatOptions" :height="'300px'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,38 +1,56 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="自定义指令:v-clipboard,用于复制文本。" style="margin-bottom: 20px;" />
|
||||
<a-alert message="基础示例" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="自定义指令:v-clipboard,用于复制文本。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基础示例。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;margin-top: 20px;"
|
||||
/>
|
||||
<div class="input__wrap">
|
||||
<a-input v-model:value="inputVal1" placeholder="请输入要复制的文本" />
|
||||
<a-button v-clipboard="inputVal1" type="primary">复制</a-button>
|
||||
<el-input v-model="inputVal1" placeholder="请输入要复制的文本" />
|
||||
<el-button v-clipboard="inputVal1" type="primary">复制</el-button>
|
||||
</div>
|
||||
|
||||
<a-alert message="自定义回调方法" style="margin-bottom: 20px;margin-top: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="自定义回调方法。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;margin-top: 20px;"
|
||||
/>
|
||||
<div class="input__wrap">
|
||||
<a-input v-model:value="inputVal2" placeholder="请输入要复制的文本" />
|
||||
<a-button
|
||||
<el-input v-model="inputVal2" placeholder="请输入要复制的文本" />
|
||||
<el-button
|
||||
v-clipboard="inputVal2"
|
||||
v-clipboard:success="clipboardSuccess"
|
||||
v-clipboard:error="clipboardSuccess"
|
||||
type="primary"
|
||||
>复制</a-button>
|
||||
>复制</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { message } from 'ant-design-vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
export default defineComponent({
|
||||
// name: 'Clipboard'
|
||||
setup() {
|
||||
const inputVal1 = ref<string>('')
|
||||
const inputVal2 = ref<string>('')
|
||||
function clipboardSuccess(val: any) {
|
||||
message.success('我是自定义成功回调:' + val.text)
|
||||
ElMessage.success('我是自定义成功回调:' + val.text)
|
||||
}
|
||||
function clipboardError() {
|
||||
message.error('我是自定义失败回调')
|
||||
ElMessage.error('我是自定义失败回调')
|
||||
}
|
||||
return {
|
||||
inputVal1, inputVal2,
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="useScrollTo,提供JS滚动过渡动画功能。" style="margin-bottom: 20px;" />
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="useScrollTo,提供JS滚动过渡动画功能。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<div class="button__wrap">
|
||||
<a-button type="primary" @click="scrollTo(100, 'scrollTop')">垂直滚动100px</a-button>
|
||||
<a-button type="primary" @click="scrollTo(800, 'scrollTop')">垂直滚动800px</a-button>
|
||||
<a-button type="primary" @click="scrollTo(100, 'scrollLeft')">水平滚动100px</a-button>
|
||||
<a-button type="primary" @click="scrollTo(500, 'scrollLeft')">水平滚动500px</a-button>
|
||||
<el-button type="primary" @click="scrollTo(100, 'scrollTop')">垂直滚动100px</el-button>
|
||||
<el-button type="primary" @click="scrollTo(800, 'scrollTop')">垂直滚动800px</el-button>
|
||||
<el-button type="primary" @click="scrollTo(100, 'scrollLeft')">水平滚动100px</el-button>
|
||||
<el-button type="primary" @click="scrollTo(500, 'scrollLeft')">水平滚动500px</el-button>
|
||||
</div>
|
||||
<div class="deom__wrap">
|
||||
<scrollbar ref="scrollContainer">
|
||||
<el-scrollbar ref="scrollContainer">
|
||||
<ul class="deom-ul__wrap">
|
||||
<li v-for="i in 100" :key="i">{{ i }}</li>
|
||||
</ul>
|
||||
</scrollbar>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -20,17 +26,13 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue'
|
||||
import { useScrollTo } from '@/hooks/useScrollTo'
|
||||
import Scrollbar from '_c/Scrollbar/index.vue'
|
||||
export default defineComponent({
|
||||
// name: 'UseScrollToDemo',
|
||||
components: {
|
||||
Scrollbar
|
||||
},
|
||||
setup() {
|
||||
const scrollContainer = ref<HTMLElement | null>(null)
|
||||
|
||||
function scrollTo(to: number, position: string): void {
|
||||
const $scrollWrapper: any = (unref(scrollContainer) as any).$.wrap
|
||||
const $scrollWrapper: any = (unref(scrollContainer) as any).wrap
|
||||
const { start } = useScrollTo({
|
||||
el: $scrollWrapper,
|
||||
position: position,
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-alert message="useWatermark,为整个系统提供水印功能。" style="margin-bottom: 20px;" />
|
||||
<a-button type="primary" @click="setWatermark('vue-antdv-admin')">创建水印</a-button>
|
||||
<a-button type="danger" @click="clear">清除水印</a-button>
|
||||
<a-button type="warning" @click="setWatermark('vue-antdv-admin-new')">重置水印</a-button>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="useWatermark,为整个系统提供水印功能。"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<el-button type="primary" @click="setWatermark('vue-antdv-admin')">创建水印</el-button>
|
||||
<el-button type="danger" @click="clear">清除水印</el-button>
|
||||
<el-button type="warning" @click="setWatermark('vue-antdv-admin-new')">重置水印</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,15 +5,12 @@
|
||||
:key="item"
|
||||
v-clipboard="generateIconCode(item)"
|
||||
>
|
||||
<a-tooltip placement="top">
|
||||
<template #title>
|
||||
{{ generateIconCode(item) }}
|
||||
</template>
|
||||
<el-tooltip placement="top" :content="generateIconCode(item)">
|
||||
<div class="icon-item">
|
||||
<svg-icon :icon-class="item" class-name="disabled" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -61,7 +61,7 @@ import { defineComponent, ref, unref, reactive, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import { permissionStore } from '_p/index/store/modules/permission'
|
||||
import config from '_p/index/config'
|
||||
import { appStore } from '_p/index/store/modules/app'
|
||||
import wsCache from '@/cache'
|
||||
|
||||
interface FormModule {
|
||||
@@ -106,7 +106,7 @@ export default defineComponent({
|
||||
permissionStore.addRouters.forEach(async(route: RouteRecordRaw) => {
|
||||
await addRoute(route.name!, route) // 动态添加可访问路由表
|
||||
})
|
||||
wsCache.set(config.user_info, form)
|
||||
wsCache.set(appStore.userInfo, form)
|
||||
permissionStore.SetIsAddRouters(true)
|
||||
push({ path: redirect.value || '/' })
|
||||
})
|
||||
|
||||
73
src/pages/index/views/table-demo/basic-table/index.vue
Normal file
73
src/pages/index/views/table-demo/basic-table/index.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 基础表格"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table v-loading="loading" :columns="columns" :data="tableData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'BasicTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,118 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
>
|
||||
<template #name="{ text }">
|
||||
<a>{{ text }}</a>
|
||||
</template>
|
||||
<template #customTitle>
|
||||
<span><smile-outlined /> Name</span>
|
||||
</template>
|
||||
<template #tags="{ text: tags }">
|
||||
<span>
|
||||
<a-tag
|
||||
v-for="tag in tags"
|
||||
:key="tag"
|
||||
:color="tag === 'loser' ? 'volcano' : tag.length > 5 ? 'geekblue' : 'green'"
|
||||
>
|
||||
{{ tag.toUpperCase() }}
|
||||
</a-tag>
|
||||
</span>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<span>
|
||||
<a>Invite -- {{ record.name }}</a>
|
||||
<a-divider type="vertical" />
|
||||
<a>Delete</a>
|
||||
<a-divider type="vertical" />
|
||||
<a class="ant-dropdown-link"> More actions <down-outlined /> </a>
|
||||
</span>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
import { SmileOutlined, DownOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
slots: { title: 'customTitle', customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age'
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address'
|
||||
},
|
||||
{
|
||||
title: 'Tags',
|
||||
key: 'tags',
|
||||
dataIndex: 'tags',
|
||||
slots: { customRender: 'tags' }
|
||||
},
|
||||
{
|
||||
title: 'Action',
|
||||
key: 'action',
|
||||
slots: { customRender: 'action' }
|
||||
}
|
||||
]
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
address: 'New York No. 1 Lake Park',
|
||||
tags: ['nice', 'developer']
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Jim Green',
|
||||
age: 42,
|
||||
address: 'London No. 1 Lake Park',
|
||||
tags: ['loser']
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
address: 'Sidney No. 1 Lake Park',
|
||||
tags: ['cool', 'teacher']
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'BasicUsage',
|
||||
components: {
|
||||
ComTable,
|
||||
SmileOutlined,
|
||||
DownOutlined
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
return {
|
||||
loading,
|
||||
columns,
|
||||
data
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
78
src/pages/index/views/table-demo/border-table/index.vue
Normal file
78
src/pages/index/views/table-demo/border-table/index.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带边框表格"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
border
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'BorderTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
111
src/pages/index/views/table-demo/custom-header/index.vue
Normal file
111
src/pages/index/views/table-demo/custom-header/index.vue
Normal file
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 自定义表头"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))"
|
||||
>
|
||||
<template #actionHeader>
|
||||
<el-input
|
||||
v-model="search"
|
||||
size="mini"
|
||||
placeholder="输入关键字搜索"
|
||||
/>
|
||||
</template>
|
||||
<template #action="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
@click="handleEdit(scope.$index, scope.row)"
|
||||
>Edit</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="danger"
|
||||
@click="handleDelete(scope.$index, scope.row)"
|
||||
>Delete</el-button>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
slots: {
|
||||
header: 'actionHeader',
|
||||
default: 'action'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎1',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎2',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎3',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎4',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'CustomHeader',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
const search = ref<string>('')
|
||||
|
||||
function handleEdit(index: number, row: any) {
|
||||
console.log(index, row)
|
||||
}
|
||||
function handleDelete(index: number, row: any) {
|
||||
console.log(index, row)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
search,
|
||||
handleEdit, handleDelete
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,198 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table :data-source="data" :columns="columns">
|
||||
<template #filterDropdown="{ setSelectedKeys, selectedKeys, confirm, clearFilters, column }">
|
||||
<div style="padding: 8px">
|
||||
<a-input
|
||||
:ref="c => (searchInput = c)"
|
||||
v-model:value="selectedKeys[0]"
|
||||
:placeholder="`Search ${column.dataIndex}`"
|
||||
style="width: 188px; margin-bottom: 8px; display: block;"
|
||||
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
|
||||
@pressEnter="handleSearch(selectedKeys, confirm, column.dataIndex)"
|
||||
/>
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
style="width: 90px; margin-right: 8px"
|
||||
@click="handleSearch(selectedKeys, confirm, column.dataIndex)"
|
||||
>
|
||||
<template #icon><SearchOutlined /></template>
|
||||
Search
|
||||
</a-button>
|
||||
<a-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
|
||||
Reset
|
||||
</a-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #filterIcon="filtered">
|
||||
<search-outlined :style="{ color: filtered ? '#108ee9' : undefined }" />
|
||||
</template>
|
||||
<template #customRender="{ text, column }">
|
||||
<span v-if="searchText && searchedColumn === column.dataIndex">
|
||||
<template
|
||||
v-for="(fragment, i) in text
|
||||
.toString()
|
||||
.split(new RegExp(`(?<=${searchText})|(?=${searchText})`, 'i'))"
|
||||
:key="i"
|
||||
>
|
||||
<mark v-if="fragment.toLowerCase() === searchText.toLowerCase()" class="highlight">
|
||||
{{ fragment }}
|
||||
</mark>
|
||||
<template v-else>{{ fragment }}</template>
|
||||
</template>
|
||||
</span>
|
||||
<template v-else>
|
||||
{{ text }}
|
||||
</template>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, getCurrentInstance } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
import { SearchOutlined } from '@ant-design/icons-vue'
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
address: 'New York No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Joe Black',
|
||||
age: 42,
|
||||
address: 'London No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Jim Green',
|
||||
age: 32,
|
||||
address: 'Sidney No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: 'Jim Red',
|
||||
age: 32,
|
||||
address: 'London No. 2 Lake Park'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'CustomMenu',
|
||||
components: {
|
||||
ComTable,
|
||||
SearchOutlined
|
||||
},
|
||||
setup() {
|
||||
const { ctx } = getCurrentInstance() as any
|
||||
|
||||
const searchText = ref<string>('')
|
||||
const searchInput = ref<any>(null)
|
||||
const searchedColumn = ref<string>('')
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
slots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
customRender: 'customRender'
|
||||
},
|
||||
onFilter: (value: string, record: any) =>
|
||||
record.name
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: (visible: boolean) => {
|
||||
if (visible) {
|
||||
setTimeout(() => {
|
||||
console.log(searchInput.value)
|
||||
searchInput.value.focus()
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
slots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
customRender: 'customRender'
|
||||
},
|
||||
onFilter: (value: string, record: any) =>
|
||||
record.age
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: (visible: boolean) => {
|
||||
if (visible) {
|
||||
setTimeout(() => {
|
||||
searchInput.value.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
slots: {
|
||||
filterDropdown: 'filterDropdown',
|
||||
filterIcon: 'filterIcon',
|
||||
customRender: 'customRender'
|
||||
},
|
||||
onFilter: (value: string, record: any) =>
|
||||
record.address
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(value.toLowerCase()),
|
||||
onFilterDropdownVisibleChange: (visible: boolean) => {
|
||||
if (visible) {
|
||||
setTimeout(() => {
|
||||
searchInput.value.focus()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
function handleSearch(selectedKeys: string[], confirm: Function, dataIndex: string) {
|
||||
confirm()
|
||||
searchText.value = selectedKeys[0]
|
||||
searchedColumn.value = dataIndex
|
||||
ctx.$forceUpdate()
|
||||
}
|
||||
|
||||
function handleReset(clearFilters: Function) {
|
||||
clearFilters()
|
||||
searchText.value = ''
|
||||
}
|
||||
|
||||
return {
|
||||
data,
|
||||
columns,
|
||||
searchText,
|
||||
searchInput,
|
||||
searchedColumn,
|
||||
handleSearch,
|
||||
handleReset
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(.highlight) {
|
||||
background-color: rgb(255, 192, 105);
|
||||
padding: 0px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,98 +0,0 @@
|
||||
<template>
|
||||
<div class="editable-cell">
|
||||
<div v-if="editable" class="editable-cell-input-wrapper">
|
||||
<a-input v-model:value="value" @pressEnter="check" />
|
||||
<check-outlined class="editable-cell-icon-check" @click="check" />
|
||||
</div>
|
||||
<div v-else class="editable-cell-text-wrapper">
|
||||
{{ value || ' ' }}
|
||||
<edit-outlined class="editable-cell-icon" @click="edit" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CheckOutlined, EditOutlined } from '@ant-design/icons-vue'
|
||||
import { defineComponent, PropType, ref } from 'vue'
|
||||
export default defineComponent({
|
||||
name: 'EditableCell',
|
||||
components: {
|
||||
CheckOutlined,
|
||||
EditOutlined
|
||||
},
|
||||
props: {
|
||||
text: {
|
||||
type: String as PropType<string>,
|
||||
default: ''
|
||||
},
|
||||
onChange: {
|
||||
type: Function as PropType<Function | null>,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const value = ref<string>(props.text)
|
||||
const editable = ref<boolean>(false)
|
||||
|
||||
function handleChange(e: any) {
|
||||
const value = e.target.value
|
||||
value.value = value
|
||||
}
|
||||
function check() {
|
||||
editable.value = false
|
||||
emit('change', value.value)
|
||||
}
|
||||
function edit() {
|
||||
editable.value = true
|
||||
}
|
||||
|
||||
return {
|
||||
value, editable,
|
||||
check, edit
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.editable-cell {
|
||||
position: relative;
|
||||
.editable-cell-input-wrapper,
|
||||
.editable-cell-text-wrapper {
|
||||
padding-right: 24px;
|
||||
}
|
||||
|
||||
.editable-cell-text-wrapper {
|
||||
padding: 5px 24px 5px 5px;
|
||||
}
|
||||
|
||||
.editable-cell-icon,
|
||||
.editable-cell-icon-check {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
width: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.editable-cell-icon {
|
||||
line-height: 18px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.editable-cell-icon-check {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.editable-cell-icon:hover,
|
||||
.editable-cell-icon-check:hover {
|
||||
color: #108ee9;
|
||||
}
|
||||
|
||||
.editable-add-btn {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
.editable-cell:hover .editable-cell-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
@@ -1,104 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<a-button class="editable-add-btn" @click="handleAdd">
|
||||
Add
|
||||
</a-button>
|
||||
<com-table bordered :data-source="dataSource" :columns="columns">
|
||||
<template #name="{ text, record }">
|
||||
<editable-cell :text="text" @change="val => onCellChange(record.key, 'name', val)" />
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<a-popconfirm
|
||||
v-if="dataSource.length"
|
||||
title="Sure to delete?"
|
||||
@confirm="onDelete(record.key)"
|
||||
>
|
||||
<a>Delete</a>
|
||||
</a-popconfirm>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
import EditableCell from './EditableCell.vue'
|
||||
export default defineComponent({
|
||||
// name: 'EditCell',
|
||||
components: {
|
||||
ComTable,
|
||||
EditableCell
|
||||
},
|
||||
setup() {
|
||||
const count = ref<number>(2)
|
||||
const dataSource = ref<any[]>([
|
||||
{
|
||||
key: '0',
|
||||
name: 'Edward King 0',
|
||||
age: '32',
|
||||
address: 'London, Park Lane no. 0'
|
||||
},
|
||||
{
|
||||
key: '1',
|
||||
name: 'Edward King 1',
|
||||
age: '32',
|
||||
address: 'London, Park Lane no. 1'
|
||||
}
|
||||
])
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
title: 'name',
|
||||
dataIndex: 'name',
|
||||
width: '30%',
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: 'age',
|
||||
dataIndex: 'age'
|
||||
},
|
||||
{
|
||||
title: 'address',
|
||||
dataIndex: 'address'
|
||||
},
|
||||
{
|
||||
title: 'operation',
|
||||
dataIndex: 'operation',
|
||||
slots: { customRender: 'operation' }
|
||||
}
|
||||
])
|
||||
|
||||
function onCellChange(key: string, dataIndex: string, value: string) {
|
||||
const newDataSource = [...dataSource.value]
|
||||
const target: any[] = newDataSource.find((item: any) => item.key === key)
|
||||
if (target) {
|
||||
target[dataIndex] = value
|
||||
dataSource.value = newDataSource
|
||||
}
|
||||
}
|
||||
function onDelete(key: string) {
|
||||
const newDataSource = [...dataSource.value]
|
||||
dataSource.value = newDataSource.filter((item: any) => item.key !== key)
|
||||
}
|
||||
function handleAdd() {
|
||||
const newData = {
|
||||
key: count.value,
|
||||
name: `Edward King ${count.value}`,
|
||||
age: 32,
|
||||
address: `London, Park Lane no. ${count.value}`
|
||||
}
|
||||
dataSource.value = [...dataSource.value, newData]
|
||||
count.value = count.value + 1
|
||||
}
|
||||
|
||||
return {
|
||||
count, dataSource, columns,
|
||||
onCellChange, onDelete, handleAdd
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,141 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table :columns="columns" :data-source="data" bordered>
|
||||
<template v-for="col in ['name', 'age', 'address']" #[col]="{ text, record }" :key="col">
|
||||
<div :key="col">
|
||||
<a-input
|
||||
v-if="record.editable"
|
||||
style="margin: -5px 0"
|
||||
:value="text"
|
||||
@change="e => handleChange(e.target.value, record.key, col)"
|
||||
/>
|
||||
<template v-else>
|
||||
{{ text }}
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<template #operation="{ record }">
|
||||
<div class="editable-row-operations">
|
||||
<span v-if="record.editable">
|
||||
<a @click="save(record.key)">Save</a>
|
||||
<a-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)">
|
||||
<a>Cancel</a>
|
||||
</a-popconfirm>
|
||||
</span>
|
||||
<span v-else>
|
||||
<a v-bind="editingKey !== '' ? { disabled: 'disabled' } : {}" @click="edit(record.key)">
|
||||
Edit
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'name',
|
||||
dataIndex: 'name',
|
||||
width: '25%',
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: 'age',
|
||||
dataIndex: 'age',
|
||||
width: '15%',
|
||||
slots: { customRender: 'age' }
|
||||
},
|
||||
{
|
||||
title: 'address',
|
||||
dataIndex: 'address',
|
||||
width: '40%',
|
||||
slots: { customRender: 'address' }
|
||||
},
|
||||
{
|
||||
title: 'operation',
|
||||
dataIndex: 'operation',
|
||||
slots: { customRender: 'operation' }
|
||||
}
|
||||
]
|
||||
|
||||
const dataList: any[] = []
|
||||
for (let i = 0; i < 100; i++) {
|
||||
dataList.push({
|
||||
key: i.toString(),
|
||||
name: `Edrward ${i}`,
|
||||
age: 32,
|
||||
address: `London Park no. ${i}`
|
||||
})
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'EditRow',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const cacheData = ref<any[]>(dataList.map(item => ({ ...item })))
|
||||
const editingKey = ref<string>('')
|
||||
const data = ref<any[]>(dataList)
|
||||
|
||||
function handleChange(value: string, key: string, column: string) {
|
||||
const newData = [...data.value]
|
||||
const target: any[] = newData.filter((item: any) => key === item.key)[0]
|
||||
if (target) {
|
||||
target[column] = value
|
||||
data.value = newData
|
||||
}
|
||||
}
|
||||
function edit(key: string) {
|
||||
const newData = [...data.value]
|
||||
const target: any = newData.filter((item: any) => key === item.key)[0]
|
||||
editingKey.value = key
|
||||
if (target) {
|
||||
target.editable = true
|
||||
data.value = newData
|
||||
}
|
||||
}
|
||||
function save(key: string) {
|
||||
const newData = [...data.value]
|
||||
const newCacheData = [...cacheData.value]
|
||||
const target: any = newData.filter((item: any) => key === item.key)[0]
|
||||
const targetCache: any[] = newCacheData.filter((item: any) => key === item.key)[0]
|
||||
if (target && targetCache) {
|
||||
delete target.editable
|
||||
data.value = newData
|
||||
Object.assign(targetCache, target)
|
||||
cacheData.value = newCacheData
|
||||
}
|
||||
editingKey.value = ''
|
||||
}
|
||||
function cancel(key: string) {
|
||||
const newData = [...data.value]
|
||||
const target: any = newData.filter((item: any) => key === item.key)[0]
|
||||
editingKey.value = ''
|
||||
if (target) {
|
||||
Object.assign(target, cacheData.value.filter((item: any) => key === item.key)[0])
|
||||
delete target.editable
|
||||
data.value = newData
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
data,
|
||||
editingKey,
|
||||
handleChange, edit, save, cancel
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.editable-row-operations a {
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
140
src/pages/index/views/table-demo/expand-row/index.vue
Normal file
140
src/pages/index/views/table-demo/expand-row/index.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 展开行"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
ref="multipleTable"
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
>
|
||||
<template #id="scope">
|
||||
<el-form label-position="left" inline class="demo-table-expand">
|
||||
<el-form-item label="商品名称">
|
||||
<span>{{ scope.row.name }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="所属店铺">
|
||||
<span>{{ scope.row.shop }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品 ID">
|
||||
<span>{{ scope.row.id }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺 ID">
|
||||
<span>{{ scope.row.shopId }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品分类">
|
||||
<span>{{ scope.row.category }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="店铺地址">
|
||||
<span>{{ scope.row.address }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="商品描述">
|
||||
<span>{{ scope.row.desc }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'id',
|
||||
type: 'expand',
|
||||
slots: {
|
||||
default: 'id'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'id',
|
||||
label: '商品ID'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '商品名称'
|
||||
},
|
||||
{
|
||||
key: 'desc',
|
||||
label: '描述'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
id: '12987122',
|
||||
name: '好滋好味鸡蛋仔',
|
||||
category: '江浙小吃、小吃零食',
|
||||
desc: '荷兰优质淡奶,奶香浓而不腻',
|
||||
address: '上海市普陀区真北路',
|
||||
shop: '王小虎夫妻店',
|
||||
shopId: '10333'
|
||||
}, {
|
||||
id: '12987123',
|
||||
name: '好滋好味鸡蛋仔',
|
||||
category: '江浙小吃、小吃零食',
|
||||
desc: '荷兰优质淡奶,奶香浓而不腻',
|
||||
address: '上海市普陀区真北路',
|
||||
shop: '王小虎夫妻店',
|
||||
shopId: '10333'
|
||||
}, {
|
||||
id: '12987125',
|
||||
name: '好滋好味鸡蛋仔',
|
||||
category: '江浙小吃、小吃零食',
|
||||
desc: '荷兰优质淡奶,奶香浓而不腻',
|
||||
address: '上海市普陀区真北路',
|
||||
shop: '王小虎夫妻店',
|
||||
shopId: '10333'
|
||||
}, {
|
||||
id: '12987126',
|
||||
name: '好滋好味鸡蛋仔',
|
||||
category: '江浙小吃、小吃零食',
|
||||
desc: '荷兰优质淡奶,奶香浓而不腻',
|
||||
address: '上海市普陀区真北路',
|
||||
shop: '王小虎夫妻店',
|
||||
shopId: '10333'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'ExpandRow',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(.demo-table-expand) {
|
||||
font-size: 0;
|
||||
label {
|
||||
width: 90px;
|
||||
color: #99a9bf;
|
||||
}
|
||||
.el-form-item {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
166
src/pages/index/views/table-demo/fixed-column-header/index.vue
Normal file
166
src/pages/index/views/table-demo/fixed-column-header/index.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定列和表头"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
border
|
||||
height="250"
|
||||
style="width: 820px;"
|
||||
>
|
||||
<template #action="scope">
|
||||
<el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
|
||||
<el-button type="text" size="small">编辑</el-button>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
fixed: true,
|
||||
width: '150'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'province',
|
||||
label: '省份',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'city',
|
||||
label: '市区',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址',
|
||||
width: '300'
|
||||
},
|
||||
{
|
||||
key: 'zip',
|
||||
label: '邮编',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
label: '操作',
|
||||
width: '100',
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'action'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1517 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1516 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1517 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1516 弄',
|
||||
zip: 200333
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'FixedColumnHeader',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function handleClick(row: any) {
|
||||
console.log(row)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
handleClick
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
133
src/pages/index/views/table-demo/fixed-column/index.vue
Normal file
133
src/pages/index/views/table-demo/fixed-column/index.vue
Normal file
@@ -0,0 +1,133 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定列"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 820px;"
|
||||
>
|
||||
<template #action="scope">
|
||||
<el-button type="text" size="small" @click="handleClick(scope.row)">查看</el-button>
|
||||
<el-button type="text" size="small">编辑</el-button>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
fixed: true,
|
||||
width: '150'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'province',
|
||||
label: '省份',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'city',
|
||||
label: '市区',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址',
|
||||
width: '300'
|
||||
},
|
||||
{
|
||||
key: 'zip',
|
||||
label: '邮编',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
label: '操作',
|
||||
width: '100',
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'action'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1517 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1516 弄',
|
||||
zip: 200333
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'FixedColumn',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function handleClick(row: any) {
|
||||
console.log(row)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
handleClick
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,46 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table :columns="columns" :data-source="data" :scroll="{ x: 1500, y: 300 }">
|
||||
<template #action>
|
||||
<a>action</a>
|
||||
</template>
|
||||
</com-table>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 固定表头"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
height="250"
|
||||
border
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{ title: 'Full Name', width: 100, dataIndex: 'name', key: 'name', fixed: 'left' },
|
||||
{ title: 'Age', width: 100, dataIndex: 'age', key: 'age', fixed: 'left' },
|
||||
{ title: 'Column 1', dataIndex: 'address', key: '1', width: 6000 },
|
||||
{ title: 'Column 2', dataIndex: 'address', key: '2', width: 150 },
|
||||
{ title: 'Column 3', dataIndex: 'address', key: '3', width: 150 },
|
||||
{ title: 'Column 4', dataIndex: 'address', key: '4', width: 150 },
|
||||
{ title: 'Column 5', dataIndex: 'address', key: '5', width: 150 },
|
||||
{ title: 'Column 6', dataIndex: 'address', key: '6', width: 150 },
|
||||
{ title: 'Column 7', dataIndex: 'address', key: '7', width: 150 },
|
||||
{ title: 'Column 8', dataIndex: 'address', key: '8' },
|
||||
{
|
||||
title: 'Action',
|
||||
key: 'operation',
|
||||
fixed: 'right',
|
||||
width: 100,
|
||||
slots: { customRender: 'action' }
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const data: any[] = []
|
||||
for (let i = 0; i < 100; i++) {
|
||||
data.push({
|
||||
key: i,
|
||||
name: `Edrward ${i}`,
|
||||
age: 32,
|
||||
address: `London Park no. ${i}`
|
||||
})
|
||||
}
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
},
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
},
|
||||
{
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'FixedHeader',
|
||||
@@ -48,9 +80,15 @@ export default defineComponent({
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
return {
|
||||
columns,
|
||||
data
|
||||
tableData,
|
||||
loading
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
164
src/pages/index/views/table-demo/fluid-height/index.vue
Normal file
164
src/pages/index/views/table-demo/fluid-height/index.vue
Normal file
@@ -0,0 +1,164 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 流体高度"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
border
|
||||
max-height="250"
|
||||
style="width: 820px;"
|
||||
>
|
||||
<template #action="scope">
|
||||
<el-button type="text" size="small" @click="deleteRow(scope.$index)">移除</el-button>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
fixed: true,
|
||||
width: '150'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'province',
|
||||
label: '省份',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'city',
|
||||
label: '市区',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址',
|
||||
width: '300'
|
||||
},
|
||||
{
|
||||
key: 'zip',
|
||||
label: '邮编',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
label: '操作',
|
||||
width: '100',
|
||||
fixed: 'right',
|
||||
slots: {
|
||||
default: 'action'
|
||||
}
|
||||
}
|
||||
]
|
||||
export default defineComponent({
|
||||
// name: 'FluidHeight',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const tableData = ref<any[]>([
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1517 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1516 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1517 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
zip: 200333
|
||||
},
|
||||
{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1516 弄',
|
||||
zip: 200333
|
||||
}
|
||||
])
|
||||
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function deleteRow(index: number) {
|
||||
tableData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
deleteRow
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
162
src/pages/index/views/table-demo/multi-header/index.vue
Normal file
162
src/pages/index/views/table-demo/multi-header/index.vue
Normal file
@@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 多级表头"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
>
|
||||
<template #address="scope">
|
||||
地址是: {{ scope.row.address }}
|
||||
</template>
|
||||
<template #action="scope">
|
||||
<el-button type="text" size="small" @click="deleteRow(scope.$index)">移除</el-button>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
fixed: true,
|
||||
width: '150'
|
||||
},
|
||||
{
|
||||
label: '配送信息',
|
||||
children: [
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
label: '地址',
|
||||
children: [
|
||||
{
|
||||
key: 'province',
|
||||
label: '省份',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'city',
|
||||
label: '市区',
|
||||
width: '120'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址',
|
||||
slots: {
|
||||
default: 'address'
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'zip',
|
||||
label: '邮编',
|
||||
width: '120'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'action',
|
||||
label: '操作',
|
||||
width: '100',
|
||||
slots: {
|
||||
default: 'action'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'MultiHeader',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const tableData = ref<any[]>([
|
||||
{
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-08',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-06',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}, {
|
||||
date: '2016-05-07',
|
||||
name: '王小虎',
|
||||
province: '上海',
|
||||
city: '普陀区',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
zip: 200333
|
||||
}
|
||||
])
|
||||
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function deleteRow(index: number) {
|
||||
tableData.value.splice(index, 1)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
deleteRow
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
102
src/pages/index/views/table-demo/multiple-choice/index.vue
Normal file
102
src/pages/index/views/table-demo/multiple-choice/index.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 多选"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
ref="multipleTable"
|
||||
v-loading="loading"
|
||||
selection
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
@selection-change="handleSelectionChange"
|
||||
/>
|
||||
|
||||
<div style="margin-top: 20px">
|
||||
<el-button @click="toggleSelection([tableData[1], tableData[2]])">切换第二、第三行的选中状态</el-button>
|
||||
<el-button @click="toggleSelection()">取消选择</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'MultipleChoice',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
const multipleTable = ref<HTMLElement | null>(null)
|
||||
function toggleSelection(rows: any[]) {
|
||||
const multipleTableRef = unref(multipleTable as any).getTableRef()
|
||||
if (rows) {
|
||||
rows.forEach(row => {
|
||||
multipleTableRef.toggleRowSelection(row)
|
||||
})
|
||||
} else {
|
||||
multipleTableRef.clearSelection()
|
||||
}
|
||||
}
|
||||
function handleSelectionChange(val: any) {
|
||||
console.log(val)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
multipleTable, toggleSelection, handleSelectionChange
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
130
src/pages/index/views/table-demo/screen-table/index.vue
Normal file
130
src/pages/index/views/table-demo/screen-table/index.vue
Normal file
@@ -0,0 +1,130 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 筛选"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<el-button @click="resetDateFilter">清除日期过滤器</el-button>
|
||||
<el-button @click="clearFilter">清除所有过滤器</el-button>
|
||||
<com-table
|
||||
ref="filterTable"
|
||||
v-loading="loading"
|
||||
row-key="date"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:default-sort="{prop: 'date', order: 'descending'}"
|
||||
>
|
||||
<template #tag="scope">
|
||||
<el-tag
|
||||
:type="scope.row.tag === '家' ? 'primary' : 'success'"
|
||||
disable-transitions
|
||||
>{{ scope.row.tag }}</el-tag>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄',
|
||||
tag: '家'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄',
|
||||
tag: '公司'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
tag: '家'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄',
|
||||
tag: '公司'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'ScreenTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const filterTable = ref<HTMLElement | null>(null)
|
||||
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
sortable: true,
|
||||
width: '180',
|
||||
columnKey: 'date',
|
||||
filters: [{ text: '2016-05-01', value: '2016-05-01' }, { text: '2016-05-02', value: '2016-05-02' }, { text: '2016-05-03', value: '2016-05-03' }, { text: '2016-05-04', value: '2016-05-04' }],
|
||||
filterMethod: filterHandler
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
},
|
||||
{
|
||||
key: 'tag',
|
||||
label: '标签',
|
||||
filters: [{ text: '家', value: '家' }, { text: '公司', value: '公司' }],
|
||||
filterMethod: filterTag,
|
||||
filterPlacement: 'bottom-end',
|
||||
slots: {
|
||||
default: 'tag'
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
function resetDateFilter() {
|
||||
const filterTableRef = unref(filterTable as any).getTableRef()
|
||||
filterTableRef.clearFilter('date')
|
||||
}
|
||||
function clearFilter() {
|
||||
const filterTableRef = unref(filterTable as any).getTableRef()
|
||||
filterTableRef.clearFilter()
|
||||
}
|
||||
function filterTag(value: string, row: any) {
|
||||
return row.tag === value
|
||||
}
|
||||
function filterHandler(value: string, row: any, column: any) {
|
||||
const property = column['property']
|
||||
return row[property] === value
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
filterTable,
|
||||
resetDateFilter, clearFilter, filterTag, filterHandler
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
96
src/pages/index/views/table-demo/single-choice/index.vue
Normal file
96
src/pages/index/views/table-demo/single-choice/index.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 单选"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
ref="singleTable"
|
||||
v-loading="loading"
|
||||
highlight-current-row
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
|
||||
<div style="margin-top: 20px">
|
||||
<el-button @click="setCurrent(tableData[1])">选中第二行</el-button>
|
||||
<el-button @click="setCurrent()">取消选择</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'SingleChoice',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
const singleTable = ref<HTMLElement | null>(null)
|
||||
function setCurrent(row: any) {
|
||||
const singleTableRef = unref(singleTable as any).getTableRef()
|
||||
singleTableRef.setCurrentRow(row)
|
||||
}
|
||||
function handleCurrentChange(val: any) {
|
||||
console.log(val)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
singleTable, setCurrent, handleCurrentChange
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
82
src/pages/index/views/table-demo/sort-table/index.vue
Normal file
82
src/pages/index/views/table-demo/sort-table/index.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 排序"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
ref="multipleTable"
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:default-sort="{prop: 'date', order: 'descending'}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'SortTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
100
src/pages/index/views/table-demo/state-table/index.vue
Normal file
100
src/pages/index/views/table-demo/state-table/index.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带状态表格"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
:row-class-name="tableRowClassName"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'StateTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function tableRowClassName({ rowIndex }: any) {
|
||||
if (rowIndex === 1) {
|
||||
return 'warning-row'
|
||||
} else if (rowIndex === 3) {
|
||||
return 'success-row'
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading,
|
||||
tableRowClassName
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(.el-table) {
|
||||
.warning-row {
|
||||
background: oldlace;
|
||||
}
|
||||
}
|
||||
|
||||
@{deep}(.el-table) {
|
||||
.success-row {
|
||||
background: #f0f9eb;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
78
src/pages/index/views/table-demo/stripe-table/index.vue
Normal file
78
src/pages/index/views/table-demo/stripe-table/index.vue
Normal file
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 带斑马纹表格"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
stripe
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
}, {
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
}, {
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'StripeTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
return {
|
||||
columns,
|
||||
tableData,
|
||||
loading
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,87 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
bordered
|
||||
>
|
||||
<template #name="{ text }">
|
||||
<a>{{ text }}</a>
|
||||
</template>
|
||||
<template #title>
|
||||
Header
|
||||
</template>
|
||||
<template #footer>
|
||||
Footer
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: 'Cash Assets',
|
||||
className: 'column-money',
|
||||
dataIndex: 'money'
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address'
|
||||
}
|
||||
]
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
money: '¥300,000.00',
|
||||
address: 'New York No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Jim Green',
|
||||
money: '¥1,256,000.00',
|
||||
address: 'London No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Joe Black',
|
||||
money: '¥120,000.00',
|
||||
address: 'Sidney No. 1 Lake Park'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TableBorder',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
return {
|
||||
loading,
|
||||
columns,
|
||||
data
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@{deep}(th.column-money),
|
||||
@{deep}(td.column-money) {
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
@@ -1,102 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table
|
||||
:loading="loading"
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
>
|
||||
<template #name="{text}">
|
||||
<a>{{ text }}</a>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: 80
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
key: 'address 1',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: 'Long Column Long Column Long Column',
|
||||
dataIndex: 'address',
|
||||
key: 'address 2',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: 'Long Column Long Column',
|
||||
dataIndex: 'address',
|
||||
key: 'address 3',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: 'Long Column',
|
||||
dataIndex: 'address',
|
||||
key: 'address 4',
|
||||
ellipsis: true
|
||||
}
|
||||
]
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
|
||||
tags: ['nice', 'developer']
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Jim Green',
|
||||
age: 42,
|
||||
address: 'London No. 2 Lake Park, London No. 2 Lake Park',
|
||||
tags: ['loser']
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
address: 'Sidney No. 1 Lake Park, Sidney No. 1 Lake Park',
|
||||
tags: ['cool', 'teacher']
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TableEllipsis',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 1000)
|
||||
return {
|
||||
loading,
|
||||
columns,
|
||||
data
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table :columns="columns" :data-source="data">
|
||||
<template #action>
|
||||
<a>Delete</a>
|
||||
</template>
|
||||
<template #expandedRowRender="{ record }">
|
||||
<p style="margin: 0">
|
||||
{{ record.description }}
|
||||
</p>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
|
||||
const columns = [
|
||||
{ title: 'Name', dataIndex: 'name', key: 'name' },
|
||||
{ title: 'Age', dataIndex: 'age', key: 'age' },
|
||||
{ title: 'Address', dataIndex: 'address', key: 'address' },
|
||||
{ title: 'Action', dataIndex: '', key: 'x', slots: { customRender: 'action' }}
|
||||
]
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: 1,
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
address: 'New York No. 1 Lake Park',
|
||||
description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.'
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: 'Jim Green',
|
||||
age: 42,
|
||||
address: 'London No. 1 Lake Park',
|
||||
description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.'
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
address: 'Sidney No. 1 Lake Park',
|
||||
description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TableExpanded',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
columns,
|
||||
data
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,107 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table
|
||||
:columns="columns"
|
||||
:row-key="record => record.sid"
|
||||
:data-source="data"
|
||||
:pagination="pagination"
|
||||
:loading="loading"
|
||||
@change="handleTableChange"
|
||||
>
|
||||
<template #name="{ text }"> {{ text }} </template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, onMounted } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
import api from '_p/index/api'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
sorter: true,
|
||||
// sortDirections: ['ascend', 'descend'],
|
||||
width: '20%',
|
||||
slots: { customRender: 'name' }
|
||||
},
|
||||
{
|
||||
title: 'Text',
|
||||
dataIndex: 'text',
|
||||
filters: [
|
||||
{ text: 'Male', value: 'male' },
|
||||
{ text: 'Female', value: 'female' }
|
||||
],
|
||||
width: '60%'
|
||||
},
|
||||
{
|
||||
title: 'Passtime',
|
||||
dataIndex: 'passtime'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TableLoad',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
const data = ref<any[]>([])
|
||||
const pagination = ref<Object>({})
|
||||
|
||||
onMounted(() => {
|
||||
fetch()
|
||||
})
|
||||
|
||||
function handleTableChange(pagination: any, filters: any, sorter: any) {
|
||||
console.log(sorter)
|
||||
const pager: any = { ...pagination }
|
||||
pager.current = pagination.current
|
||||
pagination.value = pager
|
||||
fetch({
|
||||
count: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
sortField: sorter.field,
|
||||
sortOrder: sorter.order,
|
||||
...filters
|
||||
})
|
||||
}
|
||||
|
||||
async function fetch(params = {
|
||||
page: 1,
|
||||
count: 10
|
||||
}) {
|
||||
try {
|
||||
loading.value = true
|
||||
const res = await api.common.getList({
|
||||
params
|
||||
})
|
||||
if (res) {
|
||||
const pager: any = { ...pagination.value }
|
||||
pager.total = 200
|
||||
data.value = res.result
|
||||
pagination.value = pager
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loading,
|
||||
columns,
|
||||
data,
|
||||
pagination,
|
||||
handleTableChange
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,151 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table
|
||||
:columns="columns"
|
||||
:data-source="data"
|
||||
bordered
|
||||
>
|
||||
<template #name="{ text }">
|
||||
<a>{{ text }}</a>
|
||||
</template>
|
||||
</com-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, h } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
|
||||
const renderContent = ({ text, index }: any) => {
|
||||
const obj: any = {
|
||||
children: text,
|
||||
props: {}
|
||||
}
|
||||
if (index === 4) {
|
||||
obj.props.colSpan = 0
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: '1',
|
||||
name: 'John Brown',
|
||||
age: 32,
|
||||
tel: '0571-22098909',
|
||||
phone: 18889898989,
|
||||
address: 'New York No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: 'Jim Green',
|
||||
tel: '0571-22098333',
|
||||
phone: 18889898888,
|
||||
age: 42,
|
||||
address: 'London No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
tel: '0575-22098909',
|
||||
phone: 18900010002,
|
||||
address: 'Sidney No. 1 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: 'Jim Red',
|
||||
age: 18,
|
||||
tel: '0575-22098909',
|
||||
phone: 18900010002,
|
||||
address: 'London No. 2 Lake Park'
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
name: 'Jake White',
|
||||
age: 18,
|
||||
tel: '0575-22098909',
|
||||
phone: 18900010002,
|
||||
address: 'Dublin No. 2 Lake Park'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TableMerge',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const columns = ref<any[]>([
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
customRender: ({ text, index }: any) => {
|
||||
if (index < 4) {
|
||||
return h('a', {
|
||||
attrs: {
|
||||
href: 'javascript:;'
|
||||
}
|
||||
}, text)
|
||||
}
|
||||
return {
|
||||
children: h('a', {
|
||||
attrs: {
|
||||
href: 'javascript:;'
|
||||
}
|
||||
}, text),
|
||||
props: {
|
||||
colSpan: 5
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
customRender: renderContent
|
||||
},
|
||||
{
|
||||
title: 'Home phone',
|
||||
colSpan: 2,
|
||||
dataIndex: 'tel',
|
||||
customRender: ({ text, index }: any) => {
|
||||
const obj: any = {
|
||||
children: text,
|
||||
props: {}
|
||||
}
|
||||
if (index === 2) {
|
||||
obj.props.rowSpan = 2
|
||||
}
|
||||
// These two are merged into above cell
|
||||
if (index === 3) {
|
||||
obj.props.rowSpan = 0
|
||||
}
|
||||
if (index === 4) {
|
||||
obj.props.colSpan = 0
|
||||
}
|
||||
return obj
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Phone',
|
||||
colSpan: 0,
|
||||
dataIndex: 'phone',
|
||||
customRender: renderContent
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
customRender: renderContent
|
||||
}
|
||||
])
|
||||
return {
|
||||
data,
|
||||
columns
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -1,124 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<com-table :columns="columns" :data-source="data" :row-selection="rowSelection" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import ComTable from '_c/Table'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Name',
|
||||
dataIndex: 'name',
|
||||
key: 'name'
|
||||
},
|
||||
{
|
||||
title: 'Age',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: '12%'
|
||||
},
|
||||
{
|
||||
title: 'Address',
|
||||
dataIndex: 'address',
|
||||
width: '30%',
|
||||
key: 'address'
|
||||
}
|
||||
]
|
||||
|
||||
const data = [
|
||||
{
|
||||
key: 1,
|
||||
name: 'John Brown sr.',
|
||||
age: 60,
|
||||
address: 'New York No. 1 Lake Park',
|
||||
children: [
|
||||
{
|
||||
key: 11,
|
||||
name: 'John Brown',
|
||||
age: 42,
|
||||
address: 'New York No. 2 Lake Park'
|
||||
},
|
||||
{
|
||||
key: 12,
|
||||
name: 'John Brown jr.',
|
||||
age: 30,
|
||||
address: 'New York No. 3 Lake Park',
|
||||
children: [
|
||||
{
|
||||
key: 121,
|
||||
name: 'Jimmy Brown',
|
||||
age: 16,
|
||||
address: 'New York No. 3 Lake Park'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 13,
|
||||
name: 'Jim Green sr.',
|
||||
age: 72,
|
||||
address: 'London No. 1 Lake Park',
|
||||
children: [
|
||||
{
|
||||
key: 131,
|
||||
name: 'Jim Green',
|
||||
age: 42,
|
||||
address: 'London No. 2 Lake Park',
|
||||
children: [
|
||||
{
|
||||
key: 1311,
|
||||
name: 'Jim Green jr.',
|
||||
age: 25,
|
||||
address: 'London No. 3 Lake Park'
|
||||
},
|
||||
{
|
||||
key: 1312,
|
||||
name: 'Jimmy Green sr.',
|
||||
age: 18,
|
||||
address: 'London No. 4 Lake Park'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: 'Joe Black',
|
||||
age: 32,
|
||||
address: 'Sidney No. 1 Lake Park'
|
||||
}
|
||||
]
|
||||
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys: any, selectedRows: any) => {
|
||||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows)
|
||||
},
|
||||
onSelect: (record: any, selected: any, selectedRows: any) => {
|
||||
console.log(record, selected, selectedRows)
|
||||
},
|
||||
onSelectAll: (selected: any, selectedRows: any, changeRows: any) => {
|
||||
console.log(selected, selectedRows, changeRows)
|
||||
}
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TableTree',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
columns,
|
||||
data,
|
||||
rowSelection
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@
|
||||
@change="e => setSelectedKeys(e.target.value ? [e.target.value] : [])"
|
||||
@pressEnter="handleSearch(selectedKeys, confirm, column.dataIndex)"
|
||||
/>
|
||||
<a-button
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
style="width: 90px; margin-right: 8px"
|
||||
@@ -18,10 +18,10 @@
|
||||
>
|
||||
<template #icon><SearchOutlined /></template>
|
||||
Search
|
||||
</a-button>
|
||||
<a-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
|
||||
</el-button>
|
||||
<el-button size="small" style="width: 90px" @click="handleReset(clearFilters)">
|
||||
Reset
|
||||
</a-button>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<template #filterIcon="filtered">
|
||||
|
||||
167
src/pages/index/views/table-demo/total-table/index.vue
Normal file
167
src/pages/index/views/table-demo/total-table/index.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 表尾合计行"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
border
|
||||
show-summary
|
||||
/>
|
||||
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns1"
|
||||
:data="tableData"
|
||||
border
|
||||
height="200"
|
||||
:summary-method="getSummaries"
|
||||
show-summary
|
||||
style="margin-top: 20px;"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'amount1',
|
||||
label: '数值1',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'amount2',
|
||||
label: '数值2',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'amount3',
|
||||
label: '数值4',
|
||||
sortable: true
|
||||
}
|
||||
]
|
||||
|
||||
const columns1 = [
|
||||
{
|
||||
key: 'id',
|
||||
label: 'ID'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'amount1',
|
||||
label: '数值1(元)'
|
||||
},
|
||||
{
|
||||
key: 'amount2',
|
||||
label: '数值2(元)'
|
||||
},
|
||||
{
|
||||
key: 'amount3',
|
||||
label: '数值4(元)'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
id: '12987122',
|
||||
name: '王小虎',
|
||||
amount1: '234',
|
||||
amount2: '3.2',
|
||||
amount3: 10
|
||||
}, {
|
||||
id: '12987123',
|
||||
name: '王小虎',
|
||||
amount1: '165',
|
||||
amount2: '4.43',
|
||||
amount3: 12
|
||||
}, {
|
||||
id: '12987124',
|
||||
name: '王小虎',
|
||||
amount1: '324',
|
||||
amount2: '1.9',
|
||||
amount3: 9
|
||||
}, {
|
||||
id: '12987125',
|
||||
name: '王小虎',
|
||||
amount1: '621',
|
||||
amount2: '2.2',
|
||||
amount3: 17
|
||||
}, {
|
||||
id: '12987126',
|
||||
name: '王小虎',
|
||||
amount1: '539',
|
||||
amount2: '4.1',
|
||||
amount3: 15
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TotalTable',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function getSummaries(param: any) {
|
||||
const { columns, data } = param
|
||||
const sums: any[] = []
|
||||
columns.forEach((column: any, index: number) => {
|
||||
if (index === 0) {
|
||||
sums[index] = '总价'
|
||||
return
|
||||
}
|
||||
const values = data.map((item: any) => Number(item[column.property]))
|
||||
if (!values.every((value: number) => isNaN(value))) {
|
||||
sums[index] = values.reduce((prev: number, curr: number) => {
|
||||
const value = Number(curr)
|
||||
if (!isNaN(value)) {
|
||||
return prev + curr
|
||||
} else {
|
||||
return prev
|
||||
}
|
||||
}, 0)
|
||||
sums[index] += ' 元'
|
||||
} else {
|
||||
sums[index] = 'N/A'
|
||||
}
|
||||
})
|
||||
|
||||
return sums
|
||||
}
|
||||
|
||||
return {
|
||||
columns, columns1,
|
||||
tableData,
|
||||
loading,
|
||||
getSummaries
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
181
src/pages/index/views/table-demo/tree-and-load/index.vue
Normal file
181
src/pages/index/views/table-demo/tree-and-load/index.vue
Normal file
@@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-alert
|
||||
effect="dark"
|
||||
:closable="false"
|
||||
title="基于 Element 的 Table 组件进行二次封装,实现数据驱动,支持所有 Table 参数 -- 树形数据与懒加载"
|
||||
type="info"
|
||||
style="margin-bottom: 20px;"
|
||||
/>
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns"
|
||||
:data="tableData"
|
||||
row-key="id"
|
||||
border
|
||||
default-expand-all
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
/>
|
||||
|
||||
<com-table
|
||||
v-loading="loading"
|
||||
:columns="columns1"
|
||||
:data="tableData1"
|
||||
row-key="id"
|
||||
border
|
||||
lazy
|
||||
:load="load"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
style="margin-top: 20px;"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import ComTable from '_c/Table/index.vue'
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const columns1 = [
|
||||
{
|
||||
key: 'date',
|
||||
label: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
label: '姓名'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
label: '地址'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData = [
|
||||
{
|
||||
id: 1,
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
children: [
|
||||
{
|
||||
id: 31,
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
},
|
||||
{
|
||||
id: 32,
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
const tableData1 = [
|
||||
{
|
||||
id: 1,
|
||||
date: '2016-05-02',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1518 弄'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
date: '2016-05-04',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1517 弄'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄',
|
||||
hasChildren: true
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
date: '2016-05-03',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1516 弄'
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'TreeAndLoad',
|
||||
components: {
|
||||
ComTable
|
||||
},
|
||||
setup() {
|
||||
const loading = ref<boolean>(true)
|
||||
setTimeout(() => {
|
||||
loading.value = false
|
||||
}, 2000)
|
||||
|
||||
function load(tree: any, treeNode: any, resolve: Function) {
|
||||
setTimeout(() => {
|
||||
resolve([
|
||||
{
|
||||
id: 31,
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}, {
|
||||
id: 32,
|
||||
date: '2016-05-01',
|
||||
name: '王小虎',
|
||||
address: '上海市普陀区金沙江路 1519 弄'
|
||||
}
|
||||
])
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
columns1,
|
||||
tableData,
|
||||
tableData1,
|
||||
loading,
|
||||
load
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
Reference in New Issue
Block a user