data-table
This commit is contained in:
parent
c88d526db9
commit
590ddc8076
|
|
@ -82,7 +82,13 @@ export default [
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
const List = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
|
const List = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
|
||||||
return resultSuccess(List)
|
const data = {
|
||||||
|
list: List,
|
||||||
|
page: Number(page),
|
||||||
|
limit: Number(limit),
|
||||||
|
total: count
|
||||||
|
}
|
||||||
|
return resultSuccess(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
"@vicons/antd": "^0.10.0",
|
"@vicons/antd": "^0.10.0",
|
||||||
"@vicons/ionicons5": "^0.10.0",
|
"@vicons/ionicons5": "^0.10.0",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
|
"dayjs": "^1.11.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
"pinia": "^2.0.13",
|
"pinia": "^2.0.13",
|
||||||
"vue": "^3.2.16",
|
"vue": "^3.2.16",
|
||||||
|
|
|
||||||
|
|
@ -13,27 +13,78 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="s-table">
|
<div class="s-table">
|
||||||
<n-data-table v-bind="getBindProps" />
|
<n-data-table
|
||||||
|
ref="tableElRef"
|
||||||
|
v-bind="getBindProps"
|
||||||
|
:pagination="pagination"
|
||||||
|
@update:page="updatePage"
|
||||||
|
@update:page-size="updatePageSize"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { NDataTable } from 'naive-ui'
|
import { tableProps } from './tools/props.js'
|
||||||
import { unref, computed } from 'vue'
|
import { useDataSource } from './tools/useDataSource.js'
|
||||||
|
import { usePagination } from './tools/usePagination.js'
|
||||||
|
import { ref, unref, computed, toRaw, provide } from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: 'DataTable',
|
name: 'DataTable',
|
||||||
props: {
|
props: {
|
||||||
...NDataTable.props
|
...tableProps
|
||||||
},
|
},
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
|
const getProps = computed(() => {
|
||||||
|
return { ...props }
|
||||||
|
})
|
||||||
|
|
||||||
|
/* loading--start */
|
||||||
|
const loadingRef = ref(unref(getProps).loading)
|
||||||
|
const getLoading = computed(() => unref(loadingRef))
|
||||||
|
function setLoading(loading) {
|
||||||
|
loadingRef.value = loading
|
||||||
|
}
|
||||||
|
/* loading--end */
|
||||||
|
|
||||||
|
/* pagination-start */
|
||||||
|
const { getPaginationInfo, setPagination } = usePagination(getProps)
|
||||||
|
const pagination = computed(() => toRaw(unref(getPaginationInfo)))
|
||||||
|
|
||||||
|
/* 页码切换 */
|
||||||
|
function updatePage(page) {
|
||||||
|
setPagination({ page: page })
|
||||||
|
reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页数量切换 */
|
||||||
|
function updatePageSize(size) {
|
||||||
|
setPagination({ page: 1, pageSize: size })
|
||||||
|
reload()
|
||||||
|
}
|
||||||
|
/* pagination-end */
|
||||||
|
|
||||||
|
/* tableData-start */
|
||||||
|
const tableData = ref([])
|
||||||
|
const { getDataSourceRef, getRowKey, reload } = useDataSource(getProps, { getPaginationInfo, setPagination, tableData, setLoading }, emit)
|
||||||
const getBindProps = computed(() => {
|
const getBindProps = computed(() => {
|
||||||
return {
|
return {
|
||||||
...unref(props)
|
...unref(getProps),
|
||||||
|
loading: unref(getLoading),
|
||||||
|
rowKey: unref(getRowKey),
|
||||||
|
data: unref(getDataSourceRef),
|
||||||
|
remote: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log(getBindProps)
|
|
||||||
|
const key = Symbol('s-table')
|
||||||
|
provide(key, { getBindProps })
|
||||||
|
/* tableData-end */
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getBindProps
|
getBindProps,
|
||||||
|
pagination,
|
||||||
|
updatePage,
|
||||||
|
updatePageSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { NDataTable } from 'naive-ui'
|
||||||
|
|
||||||
|
export const tableProps = {
|
||||||
|
...NDataTable.props,
|
||||||
|
/* 初始化接口请求 */
|
||||||
|
request: {
|
||||||
|
type: Function,
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
/* 分页信息 */
|
||||||
|
pagination: {
|
||||||
|
type: [Object, Boolean],
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
|
/* 分页设置信息 */
|
||||||
|
paginationSetting: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {
|
||||||
|
return {
|
||||||
|
// 当前页的字段名
|
||||||
|
pageField: 'page',
|
||||||
|
// 每页数量字段名
|
||||||
|
sizeField: 'limit',
|
||||||
|
// 接口返回的数据字段名
|
||||||
|
listField: 'list',
|
||||||
|
// 接口返回总页数字段名
|
||||||
|
totalField: 'total',
|
||||||
|
// 默认分页数量
|
||||||
|
pageSize: 10,
|
||||||
|
// 可切换每页数量集合
|
||||||
|
pageSizes: [10, 20, 30, 40, 50],
|
||||||
|
// 是否显示每页条数的选择器
|
||||||
|
showSizePicker: false,
|
||||||
|
// 是否显示快速跳转
|
||||||
|
showQuickJumper: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { ref, unref, computed, onMounted } from 'vue'
|
||||||
|
import { isBoolean } from '@/utils/is'
|
||||||
|
|
||||||
|
export function useDataSource(propsRef, { getPaginationInfo, setPagination, setLoading, tableData }, emit) {
|
||||||
|
const dataSourceRef = ref([])
|
||||||
|
|
||||||
|
async function fetch(opt) {
|
||||||
|
try {
|
||||||
|
/* 设置loading */
|
||||||
|
setLoading(true)
|
||||||
|
const { request, pagination, paginationSetting } = unref(propsRef)
|
||||||
|
/* 无接口请求中断 */
|
||||||
|
if (!request) return
|
||||||
|
/* 获取分页信息 */
|
||||||
|
const pageField = paginationSetting.pageField
|
||||||
|
const sizeField = paginationSetting.sizeField
|
||||||
|
const totalField = paginationSetting.totalField
|
||||||
|
const listField = paginationSetting.listField
|
||||||
|
|
||||||
|
let pageParams = {}
|
||||||
|
const { page = 1, pageSize = 10 } = unref(getPaginationInfo)
|
||||||
|
/* 判断是否需要分页信息 */
|
||||||
|
if ((isBoolean(pagination) && !pagination) || isBoolean(getPaginationInfo)) {
|
||||||
|
pageParams = {}
|
||||||
|
} else {
|
||||||
|
pageParams[pageField] = (opt && opt[pageField]) || page
|
||||||
|
pageParams[sizeField] = pageSize
|
||||||
|
}
|
||||||
|
const params = {
|
||||||
|
...pageParams
|
||||||
|
}
|
||||||
|
const response = await request(params)
|
||||||
|
const res = response.data
|
||||||
|
const resultTotal = res[totalField] || 0
|
||||||
|
const currentPage = res[pageField]
|
||||||
|
// 如果数据异常,需获取正确的页码再次执行
|
||||||
|
if (resultTotal) {
|
||||||
|
if (page > Math.ceil(resultTotal / pageSize)) {
|
||||||
|
setPagination({
|
||||||
|
[pageField]: Math.ceil(resultTotal / pageSize)
|
||||||
|
})
|
||||||
|
fetch(opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const resultInfo = res[listField] ? res[listField] : []
|
||||||
|
dataSourceRef.value = resultInfo
|
||||||
|
setPagination({
|
||||||
|
[pageField]: currentPage,
|
||||||
|
[totalField]: Math.ceil(resultTotal / pageSize)
|
||||||
|
})
|
||||||
|
/* 更新页码数据 */
|
||||||
|
if (opt && opt[pageField]) {
|
||||||
|
setPagination({
|
||||||
|
[pageField]: opt[pageField] || 1
|
||||||
|
})
|
||||||
|
}
|
||||||
|
emit('fetch-success', {
|
||||||
|
items: unref(resultInfo),
|
||||||
|
resultTotal
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
// emit('fetch-error', error)
|
||||||
|
dataSourceRef.value = []
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDataSourceRef = computed(() => {
|
||||||
|
const dataSource = unref(dataSourceRef)
|
||||||
|
if (!dataSource || dataSource.length === 0) {
|
||||||
|
return unref(dataSourceRef)
|
||||||
|
}
|
||||||
|
return unref(dataSourceRef)
|
||||||
|
})
|
||||||
|
|
||||||
|
function getDataSource() {
|
||||||
|
return getDataSourceRef.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTableData(values) {
|
||||||
|
dataSourceRef.value = values
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRowKey = computed(() => {
|
||||||
|
const { rowKey } = unref(propsRef)
|
||||||
|
return rowKey || (() => {
|
||||||
|
return 'key'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
async function reload(opt) {
|
||||||
|
await fetch(opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
fetch()
|
||||||
|
}, 15)
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
fetch,
|
||||||
|
getDataSourceRef,
|
||||||
|
getDataSource,
|
||||||
|
setTableData,
|
||||||
|
getRowKey,
|
||||||
|
reload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { computed, unref, ref } from 'vue'
|
||||||
|
import { isBoolean } from '@/utils/is'
|
||||||
|
|
||||||
|
export function usePagination(refProps) {
|
||||||
|
const configRef = ref({})
|
||||||
|
const getPaginationInfo = computed(() => {
|
||||||
|
const { pagination, paginationSetting } = unref(refProps)
|
||||||
|
/* 判断是否需要展示分页 */
|
||||||
|
if ((isBoolean(pagination) && !pagination)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
/* 返回配置的分页信息 */
|
||||||
|
return {
|
||||||
|
pageSize: paginationSetting.pageSize,
|
||||||
|
pageSizes: paginationSetting.pageSizes,
|
||||||
|
showSizePicker: paginationSetting.showSizePicker,
|
||||||
|
showQuickJumper: paginationSetting.showQuickJumper,
|
||||||
|
...(isBoolean(pagination) ? {} : pagination),
|
||||||
|
...unref(configRef),
|
||||||
|
pageCount: unref(configRef)[paginationSetting.totalField]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function setPagination(info) {
|
||||||
|
const paginationInfo = unref(getPaginationInfo)
|
||||||
|
configRef.value = {
|
||||||
|
...(!isBoolean(paginationInfo) ? paginationInfo : {}),
|
||||||
|
...info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPagination() {
|
||||||
|
return unref(getPaginationInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return { getPaginationInfo, setPagination, getPagination }
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="tabs-view" :class="{'tabs-view-fix': tagsMenuSetting.fixed,}">
|
<div class="tabs-view" :class="{'tabs-view-fix': tagsMenuSetting.fixed,}" :style="getChangeStyle">
|
||||||
<div class="tabs-view-main">
|
<div class="tabs-view-main">
|
||||||
<div ref="navWrap" class="tabs-card" :class="{ 'tabs-card-scrollable': scrollable }">
|
<div ref="navWrap" class="tabs-card" :class="{ 'tabs-card-scrollable': state.scrollable }">
|
||||||
<span class="tabs-card-prev" :class="{ 'tabs-card-prev-hide': !scrollable }" @click="scrollPrev">
|
<span class="tabs-card-prev" :class="{ 'tabs-card-prev-hide': !state.scrollable }" @click="scrollPrev">
|
||||||
<n-icon size="16" color="#515a6e">
|
<n-icon size="16" color="#515a6e">
|
||||||
<LeftOutlined />
|
<LeftOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
</span>
|
</span>
|
||||||
<span class="tabs-card-next" :class="{ 'tabs-card-next-hide': !scrollable }" @click="scrollNext">
|
<span class="tabs-card-next" :class="{ 'tabs-card-next-hide': !state.scrollable }" @click="scrollNext">
|
||||||
<n-icon size="16" color="#515a6e">
|
<n-icon size="16" color="#515a6e">
|
||||||
<RightOutlined />
|
<RightOutlined />
|
||||||
</n-icon>
|
</n-icon>
|
||||||
|
|
@ -31,6 +31,31 @@
|
||||||
</Draggable>
|
</Draggable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="tabs-close">
|
||||||
|
<n-dropdown
|
||||||
|
trigger="hover"
|
||||||
|
placement="bottom-end"
|
||||||
|
:options="tagsMemuOptions"
|
||||||
|
@select="closeHandleSelect"
|
||||||
|
>
|
||||||
|
<div class="tabs-close-btn">
|
||||||
|
<n-icon size="16" color="#515a6e">
|
||||||
|
<DownOutlined />
|
||||||
|
</n-icon>
|
||||||
|
</div>
|
||||||
|
</n-dropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<n-dropdown
|
||||||
|
:show="state.showDropdown"
|
||||||
|
:x="state.dropdownX"
|
||||||
|
:y="state.dropdownY"
|
||||||
|
placement="bottom-start"
|
||||||
|
:options="tagsMemuOptions"
|
||||||
|
@clickoutside="onClickOutside"
|
||||||
|
@select="closeHandleSelect"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -39,26 +64,59 @@
|
||||||
import {
|
import {
|
||||||
LeftOutlined,
|
LeftOutlined,
|
||||||
RightOutlined,
|
RightOutlined,
|
||||||
CloseOutlined
|
CloseOutlined,
|
||||||
|
DownOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
|
ColumnWidthOutlined,
|
||||||
|
MinusOutlined
|
||||||
} from '@vicons/antd'
|
} from '@vicons/antd'
|
||||||
import Draggable from 'vuedraggable'
|
import Draggable from 'vuedraggable'
|
||||||
import { reactive, computed, watch } from 'vue'
|
import { reactive, computed, watch, defineProps, ref, unref, provide, nextTick } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useTagsMenuStore } from '@/store/modules/tagsMenu.js'
|
import { useTagsMenuStore } from '@/store/modules/tagsMenu.js'
|
||||||
import { useSettingStore } from '@/store/modules/setting.js'
|
import { useSettingStore } from '@/store/modules/setting.js'
|
||||||
import { getTags, setTags } from '@/utils/tags.js'
|
import { getTags, setTags } from '@/utils/tags.js'
|
||||||
import { isString } from '@/utils/is.js'
|
import { isString } from '@/utils/is.js'
|
||||||
|
import { renderIcon } from '@/utils'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
collapsed: {
|
||||||
|
type: Boolean
|
||||||
|
},
|
||||||
|
menuMode: {
|
||||||
|
type: String,
|
||||||
|
default: 'sidebar'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/* 白名单 */
|
||||||
|
const whiteList = ['Login', 'NOT_FOUND']
|
||||||
|
/* 基础页面 */
|
||||||
|
const baseMenu = '/home'
|
||||||
|
|
||||||
/* 获取路由器 */
|
/* 获取路由器 */
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { push, replace } = router
|
const { push, replace } = router
|
||||||
|
/* 使用store数据 */
|
||||||
const tagsMenuStore = useTagsMenuStore()
|
const tagsMenuStore = useTagsMenuStore()
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore()
|
||||||
|
|
||||||
const tabsList = computed(() => tagsMenuStore.tabsList)
|
const tabsList = computed(() => tagsMenuStore.tabsList)
|
||||||
const tagsMenuSetting = computed(() => settingStore.getTagsMenuSetting)
|
const tagsMenuSetting = computed(() => settingStore.getTagsMenuSetting)
|
||||||
|
|
||||||
|
/* 组装样式 */
|
||||||
|
const getChangeStyle = computed(() => {
|
||||||
|
const { collapsed, menuMode } = props
|
||||||
|
const { cWidth, width } = unref(settingStore.getSidebarSetting)
|
||||||
|
const { fixed } = unref(settingStore.getTagsMenuSetting)
|
||||||
|
const lenNum = menuMode === 'header' ? '0px' : collapsed ? `${cWidth}px` : `${width}px`
|
||||||
|
return {
|
||||||
|
left: lenNum,
|
||||||
|
width: `calc(100% - ${!fixed ? '0px' : lenNum})`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let cacheRoutes = []
|
let cacheRoutes = []
|
||||||
const simpleRoute = getSimpleRoute(route)
|
const simpleRoute = getSimpleRoute(route)
|
||||||
try {
|
try {
|
||||||
|
|
@ -82,13 +140,15 @@ tagsMenuStore.initTabs(cacheRoutes)
|
||||||
|
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
activeKey: route.fullPath,
|
activeKey: route.fullPath,
|
||||||
scrollable: false
|
scrollable: false,
|
||||||
|
showDropdown: false,
|
||||||
|
dropdownX: 0,
|
||||||
|
dropdownY: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.fullPath,
|
() => route.fullPath,
|
||||||
(to) => {
|
(to) => {
|
||||||
console.log('to', to)
|
|
||||||
// if (whiteList.includes(route.name)) return
|
// if (whiteList.includes(route.name)) return
|
||||||
state.activeKey = to
|
state.activeKey = to
|
||||||
tagsMenuStore.addTabs(getSimpleRoute(route))
|
tagsMenuStore.addTabs(getSimpleRoute(route))
|
||||||
|
|
@ -143,27 +203,147 @@ function goPage(e) {
|
||||||
* @description: 删除项
|
* @description: 删除项
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
// 删除tab
|
|
||||||
function closeTabItem(e) {
|
function closeTabItem(e) {
|
||||||
// const { fullPath } = e
|
const { fullPath } = e
|
||||||
// const routeInfo = tabsList.value.find((item) => item.fullPath == fullPath)
|
const routeInfo = tabsList.value.find((item) => item.fullPath === fullPath)
|
||||||
// removeTab(routeInfo)
|
removeTab(routeInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description:
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
const removeTab = (route) => {
|
||||||
|
if (tabsList.value.length === 1) {
|
||||||
|
// return message.warning('这已经是最后一页,不能再关闭了!')
|
||||||
|
}
|
||||||
|
// delKeepAliveCompName()
|
||||||
|
tagsMenuStore.closeCurrentTab(route)
|
||||||
|
// 如果关闭的是当前页
|
||||||
|
if (state.activeKey === route.fullPath) {
|
||||||
|
const currentRoute = tabsList.value[Math.max(0, tabsList.value.length - 1)]
|
||||||
|
state.activeKey = currentRoute.fullPath
|
||||||
|
router.push(currentRoute)
|
||||||
|
}
|
||||||
|
// updateNavScroll()
|
||||||
|
}
|
||||||
|
|
||||||
|
// const delKeepAliveCompName = () => {
|
||||||
|
// if (route.meta.keepAlive) {
|
||||||
|
// const name = router.currentRoute.value.matched.find((item) => item.name === route.name)
|
||||||
|
// ?.components?.default.name
|
||||||
|
// if (name) {
|
||||||
|
// asyncRouteStore.keepAliveComponents = asyncRouteStore.keepAliveComponents.filter(
|
||||||
|
// (item) => item != name
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/* dropdown--start */
|
||||||
|
/* 右侧下拉菜单 */
|
||||||
|
const isCurrent = ref(false)
|
||||||
|
const tagsMemuOptions = computed(() => {
|
||||||
|
const isDisabled = unref(tabsList).length <= 1
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: '刷新当前',
|
||||||
|
key: '1',
|
||||||
|
icon: renderIcon(ReloadOutlined)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: `关闭当前`,
|
||||||
|
key: '2',
|
||||||
|
disabled: unref(isCurrent) || isDisabled,
|
||||||
|
icon: renderIcon(CloseOutlined)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '关闭其他',
|
||||||
|
key: '3',
|
||||||
|
disabled: isDisabled,
|
||||||
|
icon: renderIcon(ColumnWidthOutlined)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '关闭全部',
|
||||||
|
key: '4',
|
||||||
|
disabled: isDisabled,
|
||||||
|
icon: renderIcon(MinusOutlined)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
/* 操作右侧下拉菜单 */
|
||||||
|
const closeHandleSelect = (key) => {
|
||||||
|
switch (key) {
|
||||||
|
// 刷新
|
||||||
|
case '1':
|
||||||
|
reloadPage()
|
||||||
|
break
|
||||||
|
// 关闭
|
||||||
|
case '2':
|
||||||
|
removeTab(route)
|
||||||
|
break
|
||||||
|
// 关闭其他
|
||||||
|
case '3':
|
||||||
|
closeOther(route)
|
||||||
|
break
|
||||||
|
// 关闭所有
|
||||||
|
case '4':
|
||||||
|
closeAll()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// updateNavScroll()
|
||||||
|
state.showDropdown = false
|
||||||
|
}
|
||||||
|
/* 刷新页面 */
|
||||||
|
const reloadPage = () => {
|
||||||
|
// delKeepAliveCompName()
|
||||||
|
router.push({
|
||||||
|
path: '/redirect' + unref(route).fullPath
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/* 注入刷新页面方法 */
|
||||||
|
provide('reloadPage', reloadPage)
|
||||||
|
/* 关闭其他 */
|
||||||
|
const closeOther = (route) => {
|
||||||
|
tagsMenuStore.closeOtherTabs(route)
|
||||||
|
state.activeKey = route.fullPath
|
||||||
|
router.replace(route.fullPath)
|
||||||
|
// updateNavScroll()
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 关闭全部 */
|
||||||
|
const closeAll = () => {
|
||||||
|
tagsMenuStore.closeAllTabs()
|
||||||
|
router.replace(baseMenu)
|
||||||
|
// updateNavScroll()
|
||||||
|
}
|
||||||
|
/* dropdown--end */
|
||||||
|
/* contextMenu--start */
|
||||||
/**
|
/**
|
||||||
* @description: 右键菜单
|
* @description: 右键菜单
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
function handleContextMenu(e, item) {
|
function handleContextMenu(e, item) {
|
||||||
// e.preventDefault()
|
e.preventDefault()
|
||||||
// isCurrent.value = PageEnum.BASE_HOME_REDIRECT === item.path
|
isCurrent.value = baseMenu === item.path
|
||||||
// state.showDropdown = false
|
state.showDropdown = false
|
||||||
// nextTick().then(() => {
|
nextTick().then(() => {
|
||||||
// state.showDropdown = true
|
state.showDropdown = true
|
||||||
// state.dropdownX = e.clientX
|
state.dropdownX = e.clientX
|
||||||
// state.dropdownY = e.clientY
|
state.dropdownY = e.clientY
|
||||||
// })
|
})
|
||||||
}
|
}
|
||||||
|
function onClickOutside() {
|
||||||
|
state.showDropdown = false
|
||||||
|
}
|
||||||
|
/* contextMenu--end */
|
||||||
|
/**
|
||||||
|
* @description: 页面跳转
|
||||||
|
* @param undefined
|
||||||
|
* @param undefined
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
function go(opt, isReplace = false) {
|
function go(opt, isReplace = false) {
|
||||||
if (!opt) {
|
if (!opt) {
|
||||||
return
|
return
|
||||||
|
|
@ -258,6 +438,24 @@ function go(opt, isReplace = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabs-close {
|
||||||
|
min-width: 32px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
// background: var(--color);
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
.tabs-close-btn {
|
||||||
|
// color: var(--color);
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs-view-fix {
|
.tabs-view-fix {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useUserStore } from '@/store/modules/user'
|
import { useUserStore } from '@/store/modules/user'
|
||||||
import { usePermissionStore } from '@/store/modules/permission'
|
import { usePermissionStore } from '@/store/modules/permission'
|
||||||
import { NOT_FOUND_ROUTE } from '@/router/routes'
|
import { NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '@/router/routes'
|
||||||
import { getToken } from '@/utils/token'
|
import { getToken } from '@/utils/token'
|
||||||
|
|
||||||
const WHITE_LIST = ['/login', '/redirect']
|
const WHITE_LIST = ['/login', '/redirect']
|
||||||
|
|
@ -14,7 +14,6 @@ export function createPermissionGuard(router) {
|
||||||
next({ path: '/' })
|
next({ path: '/' })
|
||||||
} else {
|
} else {
|
||||||
const hasRoutes = !!permissionStore.permissionRoutes.length
|
const hasRoutes = !!permissionStore.permissionRoutes.length
|
||||||
console.log(permissionStore.permissionRoutes)
|
|
||||||
if (hasRoutes) {
|
if (hasRoutes) {
|
||||||
next()
|
next()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -23,6 +22,7 @@ export function createPermissionGuard(router) {
|
||||||
const routes = await permissionStore.generateRoutes()
|
const routes = await permissionStore.generateRoutes()
|
||||||
router.addRoute(routes[0])
|
router.addRoute(routes[0])
|
||||||
router.addRoute(NOT_FOUND_ROUTE)
|
router.addRoute(NOT_FOUND_ROUTE)
|
||||||
|
router.addRoute(REDIRECT_ROUTE)
|
||||||
next({ ...to, replace: true })
|
next({ ...to, replace: true })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// removeToken()
|
// removeToken()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,8 @@ export const basicRoutes = [
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: Home,
|
component: Home,
|
||||||
meta: {
|
meta: {
|
||||||
title: '首页'
|
title: '首页',
|
||||||
|
affix: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -39,6 +40,27 @@ export const NOT_FOUND_ROUTE = {
|
||||||
isHidden: true
|
isHidden: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const REDIRECT_ROUTE = {
|
||||||
|
path: '/redirect',
|
||||||
|
name: 'Redirect',
|
||||||
|
component: Layout,
|
||||||
|
meta: {
|
||||||
|
title: 'Redirect',
|
||||||
|
hideBreadcrumb: true
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '/redirect/:path(.*)',
|
||||||
|
name: 'Redirect',
|
||||||
|
component: () => import('@/views/redirect/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'Redirect',
|
||||||
|
hideBreadcrumb: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
const modules = import.meta.globEager('./modules/*.js')
|
const modules = import.meta.globEager('./modules/*.js')
|
||||||
const asyncRoutes = []
|
const asyncRoutes = []
|
||||||
Object.keys(modules).forEach((key) => {
|
Object.keys(modules).forEach((key) => {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { h } from 'vue'
|
||||||
|
import { NIcon } from 'naive-ui'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -74,3 +76,11 @@ export function debounce(method, wait, immediate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 渲染图标
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export function renderIcon(icon) {
|
||||||
|
return () => h(NIcon, null, { default: () => h(icon) })
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
<script>
|
||||||
|
import { defineComponent, onBeforeMount } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RedirectPage',
|
||||||
|
setup() {
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
onBeforeMount(() => {
|
||||||
|
const { params, query } = route
|
||||||
|
const { path } = params
|
||||||
|
router.replace({
|
||||||
|
path: '/' + (Array.isArray(path) ? path.join('/') : path),
|
||||||
|
query
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<data-table :columns="data.columns" :data="data.data" size="large">
|
<n-card>
|
||||||
<template #tableTitle>
|
<data-table :columns="data.columns" :pagination="false" :data="data.data" size="large">
|
||||||
<n-button type="primary">
|
<template #tableTitle>
|
||||||
添加角色
|
<n-button type="primary">
|
||||||
</n-button>
|
添加角色
|
||||||
</template>
|
</n-button>
|
||||||
</data-table>
|
</template>
|
||||||
|
</data-table>
|
||||||
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import dataTable from '@/components/DataTable/index.vue'
|
import dataTable from '@/components/DataTable/index.vue'
|
||||||
import Action from '@/components/DataTable/tools/action.vue'
|
import Action from '@/components/DataTable/tools/Action.vue'
|
||||||
import { getMenuList } from '@/api/system/index.js'
|
import { getMenuList } from '@/api/system/index.js'
|
||||||
import { h, onMounted } from 'vue'
|
import { h, onMounted } from 'vue'
|
||||||
import { reactive } from 'vue'
|
import { reactive } from 'vue'
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,181 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
1
|
<n-card>
|
||||||
|
<data-table
|
||||||
|
:columns="data.columns"
|
||||||
|
:row-key="(row) => row.id"
|
||||||
|
:request="loadDataTable"
|
||||||
|
size="large"
|
||||||
|
scroll-x="1200"
|
||||||
|
>
|
||||||
|
<template #tableTitle>
|
||||||
|
<n-button type="primary">
|
||||||
|
新建
|
||||||
|
</n-button>
|
||||||
|
<n-button type="primary">
|
||||||
|
删除
|
||||||
|
</n-button>
|
||||||
|
</template>
|
||||||
|
</data-table>
|
||||||
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import dataTable from '@/components/DataTable/index.vue'
|
||||||
|
import TableAction from '@/components/DataTable/tools/Action.vue'
|
||||||
|
import TableImage from '@/components/DataTable/tools/Image.vue'
|
||||||
|
import { getUserList } from '@/api/system/index.js'
|
||||||
|
import { h, onMounted, unref } from 'vue'
|
||||||
|
import { reactive } from 'vue'
|
||||||
export default {
|
export default {
|
||||||
name: '',
|
name: 'MenuPage',
|
||||||
|
components: { dataTable },
|
||||||
setup() {
|
setup() {
|
||||||
|
const data = reactive({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: '用户编号',
|
||||||
|
key: 'code',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '头像',
|
||||||
|
key: 'avatar',
|
||||||
|
align: 'center',
|
||||||
|
render(row) {
|
||||||
|
return h(TableImage, {
|
||||||
|
images: {
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
src: row.avatar
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户账号',
|
||||||
|
key: 'username',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户姓名',
|
||||||
|
key: 'realname',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户类型',
|
||||||
|
key: 'type',
|
||||||
|
align: 'center',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '角色',
|
||||||
|
key: 'roles',
|
||||||
|
align: 'center'
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
key: 'status',
|
||||||
|
align: 'center',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '部门',
|
||||||
|
key: 'deptName',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
key: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '更新时间',
|
||||||
|
key: 'updateTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 160
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
align: 'center',
|
||||||
|
width: 150,
|
||||||
|
fixed: 'right',
|
||||||
|
render(row) {
|
||||||
|
return h(TableAction, {
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '添加',
|
||||||
|
type: 'button',
|
||||||
|
props: {
|
||||||
|
type: 'primary',
|
||||||
|
onClick: play.bind(null, row)
|
||||||
|
},
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '修改',
|
||||||
|
auth: 'basic_list'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '删除',
|
||||||
|
type: 'popconfirm',
|
||||||
|
auth: 'basic_list'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
align: 'center'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
data: [],
|
||||||
|
pagination: {
|
||||||
|
pageSize: 10
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function play(row) {
|
||||||
|
console.log(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 获取用户数据
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
async function fetchList() {
|
||||||
|
const params = {
|
||||||
|
page: 1,
|
||||||
|
limit: 10
|
||||||
|
}
|
||||||
|
const res = await getUserList(params)
|
||||||
|
data.data = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = reactive({
|
||||||
|
name: 'xiaoMa'
|
||||||
|
})
|
||||||
|
|
||||||
|
const loadDataTable = async(res) => {
|
||||||
|
const _params = {
|
||||||
|
...unref(params),
|
||||||
|
...res
|
||||||
|
}
|
||||||
|
return await getUserList(_params)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchList()
|
||||||
|
})
|
||||||
|
|
||||||
|
return { data, loadDataTable }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang='scss'>
|
<style scoped lang='scss'>
|
||||||
|
.n-button+.n-button{
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue