This commit is contained in:
ktianc 2022-09-26 17:32:14 +08:00
parent 2cba7c7e2a
commit 388eb142a6
15 changed files with 317 additions and 83 deletions

View File

@ -5,7 +5,7 @@
"source.fixAll.eslint": true "source.fixAll.eslint": true
}, },
"[vue]": { "[vue]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint" "editor.defaultFormatter": "Vue.volar"
}, },
"i18n-ally.localesPaths": ["src/locales"], "i18n-ally.localesPaths": ["src/locales"],
"i18n-ally.keystyle": "nested", "i18n-ally.keystyle": "nested",

View File

@ -41,7 +41,7 @@ for (let i = 0; i < count; i++) {
export default [ export default [
// 列表接口 // 列表接口
{ {
url: '/example/list', url: '/api/example/list',
method: 'get', method: 'get',
timeout, timeout,
response: ({ query }) => { response: ({ query }) => {

View File

@ -0,0 +1,5 @@
import request from '@/config/axios'
export const getMenuListApi = (params: any): Promise<IResponse> => {
return request.get({ url: '/vadmin/auth/menus/', params })
}

View File

@ -0,0 +1,5 @@
import request from '@/config/axios'
export const getRoleListApi = (params: any): Promise<IResponse> => {
return request.get({ url: '/vadmin/auth/roles/', params })
}

View File

@ -10,8 +10,8 @@ import { set } from 'lodash-es'
export default defineComponent({ export default defineComponent({
name: 'Table', name: 'Table',
props: { props: {
pageSize: propTypes.number.def(10), limit: propTypes.number.def(10),
currentPage: propTypes.number.def(1), page: propTypes.number.def(1),
// //
selection: propTypes.bool.def(true), selection: propTypes.bool.def(true),
// schemashowOverflowTooltip, // schemashowOverflowTooltip,
@ -47,7 +47,7 @@ export default defineComponent({
default: () => [] default: () => []
} }
}, },
emits: ['update:pageSize', 'update:currentPage', 'register'], emits: ['update:limit', 'update:page', 'register'],
setup(props, { attrs, slots, emit, expose }) { setup(props, { attrs, slots, emit, expose }) {
const elTableRef = ref<ComponentRef<typeof ElTable>>() const elTableRef = ref<ComponentRef<typeof ElTable>>()
@ -57,9 +57,9 @@ export default defineComponent({
emit('register', tableRef?.$parent, elTableRef) emit('register', tableRef?.$parent, elTableRef)
}) })
const pageSizeRef = ref(props.pageSize) const limitRef = ref(props.limit)
const currentPageRef = ref(props.currentPage) const pageRef = ref(props.page)
// useTableprops // useTableprops
const outsideProps = ref<TableProps>({}) const outsideProps = ref<TableProps>({})
@ -110,7 +110,7 @@ export default defineComponent({
background: false, background: false,
pagerCount: 7, pagerCount: 7,
layout: 'sizes, prev, pager, next, jumper, ->, total', layout: 'sizes, prev, pager, next, jumper, ->, total',
pageSizes: [10, 20, 30, 40, 50, 100], limits: [10, 20, 30, 40, 50, 100],
disabled: false, disabled: false,
hideOnSinglePage: false, hideOnSinglePage: false,
total: 10 total: 10
@ -120,30 +120,30 @@ export default defineComponent({
}) })
watch( watch(
() => unref(getProps).pageSize, () => unref(getProps).limit,
(val: number) => { (val: number) => {
pageSizeRef.value = val limitRef.value = val
} }
) )
watch( watch(
() => unref(getProps).currentPage, () => unref(getProps).page,
(val: number) => { (val: number) => {
currentPageRef.value = val pageRef.value = val
} }
) )
watch( watch(
() => pageSizeRef.value, () => limitRef.value,
(val: number) => { (val: number) => {
emit('update:pageSize', val) emit('update:limit', val)
} }
) )
watch( watch(
() => currentPageRef.value, () => pageRef.value,
(val: number) => { (val: number) => {
emit('update:currentPage', val) emit('update:page', val)
} }
) )
@ -211,15 +211,8 @@ export default defineComponent({
} }
const rnderTableColumn = (columnsChildren?: TableColumn[]) => { const rnderTableColumn = (columnsChildren?: TableColumn[]) => {
const { const { columns, reserveIndex, limit, page, align, headerAlign, showOverflowTooltip } =
columns, unref(getProps)
reserveIndex,
pageSize,
currentPage,
align,
headerAlign,
showOverflowTooltip
} = unref(getProps)
return [...[renderTableExpand()], ...[renderTableSelection()]].concat( return [...[renderTableExpand()], ...[renderTableSelection()]].concat(
(columnsChildren || columns).map((v) => { (columnsChildren || columns).map((v) => {
// //
@ -227,11 +220,7 @@ export default defineComponent({
return ( return (
<ElTableColumn <ElTableColumn
type="index" type="index"
index={ index={v.index ? v.index : (index) => setIndex(reserveIndex, index, limit, page)}
v.index
? v.index
: (index) => setIndex(reserveIndex, index, pageSize, currentPage)
}
align={v.align || align} align={v.align || align}
headerAlign={v.headerAlign || headerAlign} headerAlign={v.headerAlign || headerAlign}
label={v.label} label={v.label}
@ -275,6 +264,7 @@ export default defineComponent({
data={unref(getProps).data} data={unref(getProps).data}
onSelection-change={selectionChange} onSelection-change={selectionChange}
{...unref(getBindValue)} {...unref(getBindValue)}
header-row-style="color: #000;background-color: #000;"
> >
{{ {{
default: () => rnderTableColumn(), default: () => rnderTableColumn(),
@ -284,8 +274,8 @@ export default defineComponent({
</ElTable> </ElTable>
{unref(getProps).pagination ? ( {unref(getProps).pagination ? (
<ElPagination <ElPagination
v-model:pageSize={pageSizeRef.value} v-model:limit={limitRef.value}
v-model:currentPage={currentPageRef.value} v-model:page={pageRef.value}
class="mt-10px" class="mt-10px"
{...unref(pagination)} {...unref(pagination)}
></ElPagination> ></ElPagination>

View File

@ -1,6 +1,6 @@
export type TableProps = { export type TableProps = {
pageSize?: number limit?: number
currentPage?: number page?: number
// 是否多选 // 是否多选
selection?: boolean selection?: boolean
// 是否所有的超出隐藏优先级低于schema中的showOverflowTooltip, // 是否所有的超出隐藏优先级低于schema中的showOverflowTooltip,

View File

@ -59,7 +59,7 @@ export const appModules: AppState = {
breadcrumb: true, // 面包屑 breadcrumb: true, // 面包屑
breadcrumbIcon: true, // 面包屑图标 breadcrumbIcon: true, // 面包屑图标
collapse: false, // 折叠菜单 collapse: false, // 折叠菜单
uniqueOpened: false, // 是否只保持一个子菜单的展开 uniqueOpened: true, // 是否只保持一个子菜单的展开
hamburger: true, // 折叠图标 hamburger: true, // 折叠图标
screenfull: true, // 全屏图标 screenfull: true, // 全屏图标
size: true, // 尺寸图标 size: true, // 尺寸图标

View File

@ -26,7 +26,6 @@ const service: AxiosInstance = axios.create({
service.interceptors.request.use( service.interceptors.request.use(
(config: AxiosRequestConfig) => { (config: AxiosRequestConfig) => {
const token = wsCache.get(appStore.getToken) const token = wsCache.get(appStore.getToken)
console.log('token', token)
if (token !== '') { if (token !== '') {
;(config.headers as any)['Authorization'] = token // 让每个请求携带自定义token 请根据实际情况自行修改 ;(config.headers as any)['Authorization'] = token // 让每个请求携带自定义token 请根据实际情况自行修改
} }

View File

@ -8,10 +8,8 @@ import { useI18n } from '@/hooks/web/useI18n'
const { t } = useI18n() const { t } = useI18n()
interface TableResponse<T = any> { interface TableResponse<T = any> {
total: number count: number
list: T[] data: T[]
pageNumber: number
pageSize: number
} }
interface UseTableConfig<T = any> { interface UseTableConfig<T = any> {
@ -19,17 +17,17 @@ interface UseTableConfig<T = any> {
delListApi?: (option: any) => Promise<IResponse> delListApi?: (option: any) => Promise<IResponse>
// 返回数据格式配置 // 返回数据格式配置
response: { response: {
list: string data: string
total?: string count?: string
} }
props?: TableProps props?: TableProps
} }
interface TableObject<T = any> { interface TableObject<T = any> {
pageSize: number limit: number
currentPage: number page: number
total: number count: number
tableList: T[] tableData: T[]
params: any params: any
loading: boolean loading: boolean
currentRow: Nullable<T> currentRow: Nullable<T>
@ -38,13 +36,13 @@ interface TableObject<T = any> {
export const useTable = <T = any>(config?: UseTableConfig<T>) => { export const useTable = <T = any>(config?: UseTableConfig<T>) => {
const tableObject = reactive<TableObject<T>>({ const tableObject = reactive<TableObject<T>>({
// 页数 // 页数
pageSize: 10, limit: 10,
// 当前页 // 当前页
currentPage: 1, page: 1,
// 总条数 // 总条数
total: 10, count: 10,
// 表格数据 // 表格数据
tableList: [], tableData: [],
// AxiosConfig 配置 // AxiosConfig 配置
params: {}, params: {},
// 加载中 // 加载中
@ -56,26 +54,26 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
const paramsObj = computed(() => { const paramsObj = computed(() => {
return { return {
...tableObject.params, ...tableObject.params,
pageSize: tableObject.pageSize, limit: tableObject.limit,
pageIndex: tableObject.currentPage page: tableObject.page
} }
}) })
watch( watch(
() => tableObject.currentPage, () => tableObject.page,
() => { () => {
methods.getList() methods.getList()
} }
) )
watch( watch(
() => tableObject.pageSize, () => tableObject.limit,
() => { () => {
// 当前页不为1时修改页数后会导致多次调用getList方法 // 当前页不为1时修改页数后会导致多次调用getdata方法
if (tableObject.currentPage === 1) { if (tableObject.page === 1) {
methods.getList() methods.getList()
} else { } else {
tableObject.currentPage = 1 tableObject.page = 1
methods.getList() methods.getList()
} }
} }
@ -102,20 +100,14 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
} }
const delData = async (ids: string[] | number[]) => { const delData = async (ids: string[] | number[]) => {
const res = await (config?.delListApi && config?.delListApi(ids)) if (config?.delListApi) {
if (res) { const res = await config.delListApi(ids)
ElMessage.success(t('common.delSuccess')) if (res) {
ElMessage.success(t('common.delSuccess'))
// 计算出临界点 methods.getList()
const currentPage = }
tableObject.total % tableObject.pageSize === ids.length || tableObject.pageSize === 1 } else {
? tableObject.currentPage > 1 ElMessage.error('删除失败,请配置删除接口!')
? tableObject.currentPage - 1
: tableObject.currentPage
: tableObject.currentPage
tableObject.currentPage = currentPage
methods.getList()
} }
} }
@ -126,8 +118,8 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
tableObject.loading = false tableObject.loading = false
}) })
if (res) { if (res) {
tableObject.tableList = get(res.data || {}, config?.response.list as string) tableObject.tableData = get(res || {}, config?.response.data as string)
tableObject.total = get(res.data || {}, config?.response?.total as string) || 0 tableObject.count = get(res || {}, config?.response.count as string) || 0
} }
}, },
setProps: async (props: TableProps = {}) => { setProps: async (props: TableProps = {}) => {
@ -144,16 +136,16 @@ export const useTable = <T = any>(config?: UseTableConfig<T>) => {
}, },
// 与Search组件结合 // 与Search组件结合
setSearchParams: (data: Recordable) => { setSearchParams: (data: Recordable) => {
tableObject.currentPage = 1 tableObject.page = 1
tableObject.params = Object.assign(tableObject.params, { tableObject.params = Object.assign(tableObject.params, {
pageSize: tableObject.pageSize, limit: tableObject.limit,
pageIndex: tableObject.currentPage, pageIndex: tableObject.page,
...data ...data
}) })
methods.getList() methods.getList()
}, },
// 删除数据 // 删除数据
delList: async (ids: string[] | number[], multiple: boolean, message = true) => { deldata: async (ids: string[] | number[], multiple: boolean, message = true) => {
const tableRef = await getTable() const tableRef = await getTable()
if (multiple) { if (multiple) {
if (!tableRef?.selections.length) { if (!tableRef?.selections.length) {

View File

@ -57,7 +57,6 @@ router.beforeEach(async (to, from, next) => {
const redirect = decodeURIComponent(redirectPath as string) const redirect = decodeURIComponent(redirectPath as string)
const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect } const nextData = to.path === redirect ? { ...to, replace: true } : { path: redirect }
permissionStore.setIsAddRouters(true) permissionStore.setIsAddRouters(true)
console.log('nextData', nextData)
next(nextData) next(nextData)
} }
} else { } else {

View File

@ -1,7 +1,88 @@
<script setup lang="ts"></script> <script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { Table } from '@/components/Table'
import { getMenuListApi } from '@/api/vadmin/auth/menu'
import { TableData } from '@/api/table/types'
import { reactive } from 'vue'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n'
import { ElButton } from 'element-plus'
const { t } = useI18n()
const columns = reactive<TableColumn[]>([
{
field: 'title',
label: '菜单名称'
},
{
field: 'icon',
label: '图标'
},
{
field: 'order',
label: '排序'
},
{
field: 'menu_type',
label: '菜单类型'
},
{
field: 'perms',
label: '权限标识'
},
{
field: 'component',
label: '组件路径'
},
{
field: 'action',
width: '260px',
label: t('tableDemo.action'),
form: {
show: false
},
detail: {
show: false
}
}
])
const { register, tableObject, methods } = useTable<TableData>({
getListApi: getMenuListApi,
response: {
data: 'data'
},
props: {
columns
}
})
const { getList } = methods
getList()
</script>
<template> <template>
<div></div> <ContentWrap>
<Table
:data="tableObject.tableData"
:loading="tableObject.loading"
:selection="false"
row-key="id"
@register="register"
>
<template #action="{}">
<ElButton type="primary" text>
{{ t('exampleDemo.edit') }}
</ElButton>
<ElButton type="success" text>
{{ t('exampleDemo.detail') }}
</ElButton>
<ElButton type="danger" text>
{{ t('exampleDemo.del') }}
</ElButton>
</template>
</Table>
</ContentWrap>
</template> </template>
<style scoped lang="less"></style>

View File

@ -0,0 +1,97 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { Table } from '@/components/Table'
import { getRoleListApi } from '@/api/vadmin/auth/role'
import { TableData } from '@/api/table/types'
import { reactive } from 'vue'
import { useTable } from '@/hooks/web/useTable'
import { useI18n } from '@/hooks/web/useI18n'
import { ElButton } from 'element-plus'
const { t } = useI18n()
const columns = reactive<TableColumn[]>([
{
field: 'id',
label: '角色编号'
},
{
field: 'name',
label: '角色名称'
},
{
field: 'role_key',
label: '权限字符'
},
{
field: 'index',
label: '显示顺序'
},
{
field: 'is_active',
label: '状态'
},
{
field: 'is_admin',
label: '最高权限'
},
{
field: 'create_datetime',
label: '创建时间'
},
{
field: 'action',
width: '260px',
label: t('tableDemo.action'),
form: {
show: false
},
detail: {
show: false
}
}
])
const { register, tableObject, methods } = useTable<TableData>({
getListApi: getRoleListApi,
response: {
data: 'data',
count: 'count'
},
props: {
columns
}
})
const { getList } = methods
getList()
</script>
<template>
<ContentWrap>
<Table
v-model:limit="tableObject.limit"
v-model:page="tableObject.page"
:data="tableObject.tableData"
:loading="tableObject.loading"
:selection="false"
:pagination="{
total: tableObject.count
}"
@register="register"
>
<template #action="{}">
<ElButton type="primary" text>
{{ t('exampleDemo.edit') }}
</ElButton>
<ElButton type="success" text>
{{ t('exampleDemo.detail') }}
</ElButton>
<ElButton type="danger" text>
{{ t('exampleDemo.del') }}
</ElButton>
</template>
</Table>
</ContentWrap>
</template>

View File

@ -0,0 +1,66 @@
<script setup lang="ts">
import { ContentWrap } from '@/components/ContentWrap'
import { Table } from '@/components/Table'
import { getTableListApi } from '@/api/table'
import { TableData } from '@/api/table/types'
import { reactive } from 'vue'
import { useTable } from '@/hooks/web/useTable'
const columns = reactive<TableColumn[]>([
{
field: 'index',
label: 'index',
type: 'index'
},
{
field: 'title',
label: 'title'
},
{
field: 'author',
label: 'author'
},
{
field: 'display_time',
label: 'displayTime'
},
{
field: 'pageviews',
label: 'pageviews'
},
{
field: 'action',
label: 'action'
}
])
const { register, tableObject, methods } = useTable<TableData>({
getListApi: getTableListApi,
response: {
list: 'list',
total: 'total'
},
props: {
columns
}
})
const { getList } = methods
getList()
</script>
<template>
<ContentWrap>
<Table
v-model:pageSize="tableObject.pageSize"
v-model:currentPage="tableObject.currentPage"
:data="tableObject.tableList"
:loading="tableObject.loading"
:pagination="{
total: tableObject.total
}"
@register="register"
/>
</ContentWrap>
</template>

View File

@ -35,6 +35,7 @@ declare interface AxiosConfig {
} }
declare interface IResponse<T = any> { declare interface IResponse<T = any> {
count: {}
code: string code: string
data: T extends any ? T : T & any data: T extends any ? T : T & any
message: string message: string

View File

@ -16,7 +16,6 @@ from core.validator import ValiDatetime
class Menu(BaseModel): class Menu(BaseModel):
title: str title: str
title_zh: Optional[str] = None
icon: Optional[str] = None icon: Optional[str] = None
component: str component: str
path: str path: str