<template> | |||||
<template v-if="isFilter"> | |||||
<n-tag | |||||
v-for="(item,index) in getData.data" | |||||
:key="`tag_${index}`" | |||||
v-bind="getProps" | |||||
:color="getFilter(item[getData.rowKey]).color || getProps.color" | |||||
> | |||||
{{ getFilter(item[getData.rowKey]).label }} | |||||
</n-tag> | |||||
</template> | |||||
<template v-else> | |||||
<n-tag v-for="(item,index) in getData.data" :key="`tag_${index}`" v-bind="getProps"> | |||||
{{ item[getData.rowKey] }} | |||||
</n-tag> | |||||
</template> | |||||
</template> | |||||
<script> | |||||
import { defineComponent, computed, unref } from 'vue' | |||||
export default defineComponent({ | |||||
name: 'TableTags', | |||||
props: { | |||||
/* 展示的数据 */ | |||||
data: { | |||||
type: Object, | |||||
defalut: [], | |||||
required: true | |||||
}, | |||||
/* 展示数据取的字段 */ | |||||
rowKey: { | |||||
type: String, | |||||
default: 'name' | |||||
}, | |||||
/* 过滤的数据 */ | |||||
// filters: [ | |||||
// { | |||||
// key: '', | |||||
// label: '', | |||||
// color: {} | |||||
// } | |||||
// ], | |||||
filters: { | |||||
type: Array, | |||||
default: null | |||||
}, | |||||
/* tag标签的属性 */ | |||||
tags: { | |||||
type: Object, | |||||
default: null | |||||
} | |||||
}, | |||||
setup(props, { emit }) { | |||||
const isFilter = computed(() => { | |||||
return !!(props.filters) | |||||
}) | |||||
const { filters } = unref(props) | |||||
function getFilter(value) { | |||||
const data = filters.find(item => { | |||||
return item.key === value | |||||
}) | |||||
return data | |||||
} | |||||
/* 获取传递的数据 */ | |||||
const getData = computed(() => { | |||||
return { | |||||
rowKey: unref(props.rowKey), | |||||
data: { ...unref(props.data) }, | |||||
filters: { ...unref(props.filters) } | |||||
} | |||||
}) | |||||
/* 获取tags的属性 */ | |||||
const getProps = computed(() => { | |||||
return { | |||||
...unref(props.tags), | |||||
closable: false, | |||||
bordered: props.tags?.bordered || false | |||||
} | |||||
}) | |||||
return { | |||||
isFilter, | |||||
getFilter, | |||||
getData, | |||||
getProps | |||||
} | |||||
} | |||||
}) | |||||
</script> | |||||
<style scoped lang='scss'> | |||||
.n-tag{ | |||||
background: transparent; | |||||
} | |||||
</style> |
<template> | |||||
<!-- <n-data-table> | |||||
n-data-table | |||||
</n-data-table> --> | |||||
<div class="table-toolbar"> | |||||
<!--顶部左侧区域--> | |||||
<div class="flex items-center table-toolbar-left"> | |||||
<slot name="tableTitle" /> | |||||
</div> | |||||
<div class="flex items-center table-toolbar-right"> | |||||
<!--顶部右侧区域--> | |||||
<slot name="toolbar" /> | |||||
<!--刷新--> | |||||
<!-- <n-tooltip trigger="hover"> | |||||
<template #trigger> | |||||
<div class="table-toolbar-right-icon" @click="reload"> | |||||
<n-icon size="18"> | |||||
<ReloadOutlined /> | |||||
</n-icon> | |||||
</div> | |||||
</template> --> | |||||
<span @click="reload">刷新</span> | |||||
<!-- </n-tooltip> --> | |||||
<!--表格设置单独抽离成组件--> | |||||
<!-- <ColumnSetting /> --> | |||||
</div> | |||||
</div> | |||||
<div class="s-table"> | |||||
<n-data-table | |||||
ref="tableElRef" | |||||
v-bind="getBindValues" | |||||
:pagination="pagination" | |||||
> | |||||
<template v-for="item in Object.keys($slots)" #[item]="data" :key="item"> | |||||
<slot :name="item" v-bind="data" /> | |||||
</template> | |||||
</n-data-table> | |||||
</div> | |||||
</template> | |||||
<script> | |||||
import { tableProps } from './tools/props.js' | |||||
import { useDataSource } from './tools/useDataSource.js' | |||||
import { usePagination } from './tools/usePagination.js' | |||||
import { unref, ref, computed, toRaw } from 'vue' | |||||
export default { | |||||
name: 'DataTable', | |||||
props: { | |||||
...tableProps | |||||
}, | |||||
emits: [ | |||||
'fetch-success', | |||||
'fetch-error', | |||||
'update:checked-row-keys', | |||||
'edit-end', | |||||
'edit-cancel', | |||||
'edit-row-end', | |||||
'edit-change' | |||||
], | |||||
setup(props, { emit }) { | |||||
const loadingRef = ref(unref(props).loading) | |||||
const getLoading = computed(() => unref(loadingRef)) | |||||
function setLoading(loading) { | |||||
loadingRef.value = loading | |||||
} | |||||
/* pagination-start */ | |||||
const pagination = computed(() => toRaw(unref(getPaginationInfo))) | |||||
const { getPaginationInfo, setPagination } = usePagination(props) | |||||
/* pagination-end */ | |||||
/* tableData-start */ | |||||
const tableData = ref([]) | |||||
const { getDataSourceRef, reload } = useDataSource(props, { getPaginationInfo, setPagination, tableData, setLoading }, emit) | |||||
// 组装表格信息 | |||||
const getBindValues = computed(() => { | |||||
const tableData = unref(getDataSourceRef) | |||||
return { | |||||
...unref(props), | |||||
loading: unref(getLoading), | |||||
// columns: toRaw(unref(getPageColumns)), | |||||
// rowKey: unref(getRowKey), | |||||
data: tableData, | |||||
// size: unref(getTableSize), | |||||
remote: true, | |||||
'max-height': 'auto' | |||||
} | |||||
}) | |||||
/* tableData-end */ | |||||
return { | |||||
pagination, | |||||
fetch, | |||||
reload, | |||||
getBindValues | |||||
} | |||||
} | |||||
} | |||||
</script> | |||||
<style scoped lang='scss'> | |||||
.table-toolbar { | |||||
display: flex; | |||||
justify-content: space-between; | |||||
padding: 0 0 16px 0; | |||||
.table-toolbar-left { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: flex-start; | |||||
flex: 1; | |||||
} | |||||
.table-toolbar-right { | |||||
display: flex; | |||||
justify-content: flex-end; | |||||
flex: 1; | |||||
.table-toolbar-icon { | |||||
margin-left: 12px; | |||||
font-size: 16px; | |||||
cursor: pointer; | |||||
color: var(--text-color); | |||||
&:hover { | |||||
color: #1890ff; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.table-toolbar-inner-popover-title { | |||||
padding: 2px 0; | |||||
} | |||||
</style> |
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: 'pageSize', | |||||
// 接口返回的数据字段名 | |||||
listField: 'list', | |||||
// 接口返回总页数字段名 | |||||
totalField: 'pageCount', | |||||
// 默认分页数量 | |||||
defaultPageSize: 10, | |||||
// 可切换每页数量集合 | |||||
pageSizes: [10, 20, 30, 40, 50] | |||||
} | |||||
} | |||||
} | |||||
} |
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 { | |||||
// setLoading(true) | |||||
const { request, pagination } = unref(propsRef) | |||||
/* 无接口请求中断 */ | |||||
if (!request) return | |||||
/* 获取分页信息 */ | |||||
const paginationSetting = propsRef.paginationSetting | |||||
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 res = await request(params) | |||||
console.log('res', res) | |||||
const resultTotal = res[totalField] || 0 | |||||
const currentPage = res[pageField] | |||||
// // 如果数据异常,需获取正确的页码再次执行 | |||||
// if (resultTotal) { | |||||
// if (page > resultTotal) { | |||||
// setPagination({ | |||||
// [pageField]: resultTotal | |||||
// }) | |||||
// fetch(opt) | |||||
// } | |||||
// } | |||||
const resultInfo = res[listField] ? res[listField] : [] | |||||
dataSourceRef.value = resultInfo | |||||
setPagination({ | |||||
[pageField]: currentPage, | |||||
[totalField]: resultTotal | |||||
}) | |||||
// 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() { | |||||
console.log(getDataSourceRef.value) | |||||
return getDataSourceRef.value | |||||
} | |||||
function setTableData(values) { | |||||
dataSourceRef.value = values | |||||
} | |||||
onMounted(() => { | |||||
setTimeout(() => { | |||||
fetch() | |||||
}, 15) | |||||
}) | |||||
return { | |||||
fetch, | |||||
getDataSourceRef, | |||||
getDataSource, | |||||
setTableData | |||||
} | |||||
} |
import { computed, unref, ref } from 'vue' | |||||
import { isBoolean } from '@/utils/is' | |||||
export function usePagination(refProps) { | |||||
const configRef = ref({}) | |||||
const show = ref(true) | |||||
console.log('configRef', configRef) | |||||
console.log('refProps', refProps) | |||||
const getPaginationInfo = computed(() => { | |||||
const { pagination, paginationSetting } = unref(refProps) | |||||
if (!unref(show) || (isBoolean(pagination) && !pagination)) { | |||||
return false | |||||
} | |||||
return { | |||||
pageSize: paginationSetting.defaultPageSize, | |||||
pageSizes: paginationSetting.pageSizes, | |||||
showSizePicker: true, | |||||
showQuickJumper: true, | |||||
...(isBoolean(pagination) ? {} : pagination), | |||||
...unref(configRef), | |||||
pageCount: unref(configRef)[paginationSetting.totalField] | |||||
} | |||||
}) | |||||
function setPagination(info) { | |||||
const paginationInfo = unref(getPaginationInfo) | |||||
configRef.value = { | |||||
...(!isBoolean(paginationInfo) ? paginationInfo : {}), | |||||
...info | |||||
} | |||||
} | |||||
return { getPaginationInfo, setPagination } | |||||
} |
return generateOptions(permissionStore.routes, '') | return generateOptions(permissionStore.routes, '') | ||||
}) | }) | ||||
console.log('getMenuOptions', getMenuOptions) | |||||
function resolvePath(basePath, path) { | function resolvePath(basePath, path) { | ||||
if (isExternal(path)) return path | if (isExternal(path)) return path | ||||
return ( | return ( |
const res = await getMenu() | const res = await getMenu() | ||||
if (res.code === 0) { | if (res.code === 0) { | ||||
const result = dataArrayToRoutes(res.data) | const result = dataArrayToRoutes(res.data) | ||||
console.log(result) | |||||
this.accessRoutes = result | this.accessRoutes = result | ||||
return Promise.resolve(result) | return Promise.resolve(result) | ||||
} else { | } else { |
<n-card> | <n-card> | ||||
<data-table | <data-table | ||||
:columns="data.columns" | :columns="data.columns" | ||||
:data="data.data" | |||||
:pagination="data.pagination" | |||||
:row-key="(row) => row.id" | :row-key="(row) => row.id" | ||||
:request="loadDataTable" | :request="loadDataTable" | ||||
size="large" | size="large" | ||||
> | > | ||||
<template #tableTitle> | <template #tableTitle> | ||||
<n-button type="primary" @click="handleUser"> 新建 </n-button> | <n-button type="primary" @click="handleUser"> 新建 </n-button> | ||||
<n-button type="primary" @click="deleteUsers"> 删除 </n-button> | |||||
<!-- <n-button type="primary" @click="deleteUsers"> 删除 </n-button> --> | |||||
</template> | </template> | ||||
</data-table> | </data-table> | ||||
</n-card> | </n-card> | ||||
</div> | </div> | ||||
<!-- 新增、编辑弹窗 --> | <!-- 新增、编辑弹窗 --> | ||||
<user-modal v-model:visible="data.modalShow" :row="rowData" :title="modalTitle" /> | |||||
<user-modal v-if="data.modalShow" v-model:visible="data.modalShow" :row="rowData" :title="modalTitle" /> | |||||
</template> | </template> | ||||
<script> | <script> | ||||
import dataTable from '@/components/DataTable/index.vue' | import dataTable from '@/components/DataTable/index.vue' | ||||
import TableAction from '@/components/DataTable/tools/Action.vue' | import TableAction from '@/components/DataTable/tools/Action.vue' | ||||
import TableImage from '@/components/DataTable/tools/Image.vue' | import TableImage from '@/components/DataTable/tools/Image.vue' | ||||
import TableTags from '@/components/DataTable/tools/Tags.vue' | |||||
import { getUserList } from '@/api/system/user/index.js' | import { getUserList } from '@/api/system/user/index.js' | ||||
import { h, onMounted, unref, ref } from 'vue' | |||||
import { h, unref, ref } from 'vue' | |||||
import { reactive } from 'vue' | import { reactive } from 'vue' | ||||
import UserModal from './components/UserModal.vue' | import UserModal from './components/UserModal.vue' | ||||
export default { | export default { | ||||
{ | { | ||||
title: '角色', | title: '角色', | ||||
key: 'roles', | key: 'roles', | ||||
align: 'center' | |||||
align: 'center', | |||||
render(row) { | |||||
return h(TableTags, { | |||||
data: row.roles | |||||
}) | |||||
} | |||||
}, | }, | ||||
{ | { | ||||
title: '状态', | title: '状态', | ||||
} | } | ||||
} | } | ||||
], | ], | ||||
data: [], | |||||
pagination: { | |||||
pageSize: 10 | |||||
}, | |||||
modalShow: false | modalShow: false | ||||
}) | }) | ||||
const modalTitle = ref('添加用户') | const modalTitle = ref('添加用户') | ||||
data.modalShow = true | data.modalShow = true | ||||
} | } | ||||
/** | |||||
* @description: 获取用户数据 | |||||
* @return {*} | |||||
*/ | |||||
async function fetchList() { | |||||
const params = { | |||||
page: 1, | |||||
limit: 10 | |||||
} | |||||
const res = await getUserList(params) | |||||
data.data = res.data.list | |||||
} | |||||
const params = reactive({ | const params = reactive({ | ||||
name: 'xiaoMa' | |||||
name: '' | |||||
}) | }) | ||||
const loadDataTable = async(res) => { | const loadDataTable = async(res) => { | ||||
modalTitle.value = '添加用户' | modalTitle.value = '添加用户' | ||||
data.modalShow = true | data.modalShow = true | ||||
} | } | ||||
onMounted(() => { | |||||
fetchList() | |||||
}) | |||||
return { data, loadDataTable, handleUser, rowData, modalTitle } | return { data, loadDataTable, handleUser, rowData, modalTitle } | ||||
} | } |