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) | |||||
} | } | ||||
} | } | ||||
] | ] |
"@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", |
</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 { unref, computed } from 'vue' | |||||
import { tableProps } from './tools/props.js' | |||||
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 | |||||
} | } | ||||
} | } | ||||
} | } |
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 | |||||
} | |||||
} | |||||
} | |||||
} |
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 | |||||
} | |||||
} |
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 } | |||||
} |
<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 }"> | |||||
<span class="tabs-card-prev" :class="{ 'tabs-card-prev-hide': !scrollable }" @click="scrollPrev"> | |||||
<div ref="navWrap" class="tabs-card" :class="{ 'tabs-card-scrollable': state.scrollable }"> | |||||
<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> | ||||
</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> | ||||
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 { | ||||
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)) | ||||
* @description: 删除项 | * @description: 删除项 | ||||
* @return {*} | * @return {*} | ||||
*/ | */ | ||||
// 删除tab | |||||
function closeTabItem(e) { | function closeTabItem(e) { | ||||
// const { fullPath } = e | |||||
// const routeInfo = tabsList.value.find((item) => item.fullPath == fullPath) | |||||
// removeTab(routeInfo) | |||||
const { fullPath } = e | |||||
const routeInfo = tabsList.value.find((item) => item.fullPath === fullPath) | |||||
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() | |||||
// isCurrent.value = PageEnum.BASE_HOME_REDIRECT === item.path | |||||
// state.showDropdown = false | |||||
// nextTick().then(() => { | |||||
// state.showDropdown = true | |||||
// state.dropdownX = e.clientX | |||||
// state.dropdownY = e.clientY | |||||
// }) | |||||
e.preventDefault() | |||||
isCurrent.value = baseMenu === item.path | |||||
state.showDropdown = false | |||||
nextTick().then(() => { | |||||
state.showDropdown = true | |||||
state.dropdownX = e.clientX | |||||
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 | ||||
} | } | ||||
} | } | ||||
} | } | ||||
.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 { |
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'] | ||||
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 { | ||||
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() |
name: 'Home', | name: 'Home', | ||||
component: Home, | component: Home, | ||||
meta: { | meta: { | ||||
title: '首页' | |||||
title: '首页', | |||||
affix: true | |||||
} | } | ||||
} | } | ||||
] | ] | ||||
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) => { |
import { h } from 'vue' | |||||
import { NIcon } from 'naive-ui' | |||||
import dayjs from 'dayjs' | import dayjs from 'dayjs' | ||||
/** | /** | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/** | |||||
* @description: 渲染图标 | |||||
* @return {*} | |||||
*/ | |||||
export function renderIcon(icon) { | |||||
return () => h(NIcon, null, { default: () => h(icon) }) | |||||
} |
<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> |
<template> | <template> | ||||
<div> | <div> | ||||
<data-table :columns="data.columns" :data="data.data" size="large"> | |||||
<template #tableTitle> | |||||
<n-button type="primary"> | |||||
添加角色 | |||||
</n-button> | |||||
</template> | |||||
</data-table> | |||||
<n-card> | |||||
<data-table :columns="data.columns" :pagination="false" :data="data.data" size="large"> | |||||
<template #tableTitle> | |||||
<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 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' |
<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> |