Commit f831b43dec4d9413f5f0d6e43e51e6ee3b5ebd6b
1 parent
6f8384af
feat: 封装xTable 组件
Showing
8 changed files
with
358 additions
and
0 deletions
yudao-ui-admin-vue3/src/components/XTable/index.ts
0 → 100644
yudao-ui-admin-vue3/src/components/XTable/src/XTable.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <VxeGrid v-bind="getProps" ref="xGrid" :class="`${prefixCls}`" class="xtable-scrollbar"> | |
| 3 | + <template #[item]="data" v-for="item in Object.keys($slots)" :key="item"> | |
| 4 | + <slot :name="item" v-bind="data || {}"></slot> | |
| 5 | + </template> | |
| 6 | + </VxeGrid> | |
| 7 | +</template> | |
| 8 | +<script lang="ts" setup name="XTable"> | |
| 9 | +import { computed, PropType, ref, unref, useAttrs, watch } from 'vue' | |
| 10 | +import { SizeType, VxeGridInstance } from 'vxe-table' | |
| 11 | +import { useAppStore } from '@/store/modules/app' | |
| 12 | +import { useDesign } from '@/hooks/web/useDesign' | |
| 13 | +import { XTableProps } from './type' | |
| 14 | +import { isBoolean, isFunction } from '@/utils/is' | |
| 15 | + | |
| 16 | +const appStore = useAppStore() | |
| 17 | + | |
| 18 | +const { getPrefixCls } = useDesign() | |
| 19 | +const prefixCls = getPrefixCls('x-vxe-table') | |
| 20 | + | |
| 21 | +const attrs = useAttrs() | |
| 22 | +const emit = defineEmits(['register']) | |
| 23 | + | |
| 24 | +const props = defineProps({ | |
| 25 | + options: { | |
| 26 | + type: Object as PropType<XTableProps>, | |
| 27 | + default: () => {} | |
| 28 | + } | |
| 29 | +}) | |
| 30 | +const innerProps = ref<Partial<XTableProps>>() | |
| 31 | + | |
| 32 | +const getProps = computed(() => { | |
| 33 | + const options = innerProps.value || props.options | |
| 34 | + options.size = currentSize as any | |
| 35 | + options.height = 700 | |
| 36 | + getColumnsConfig(options) | |
| 37 | + getProxyConfig(options) | |
| 38 | + getPageConfig(options) | |
| 39 | + getToolBarConfig(options) | |
| 40 | + // console.log(options); | |
| 41 | + return { | |
| 42 | + ...options, | |
| 43 | + ...attrs | |
| 44 | + } | |
| 45 | +}) | |
| 46 | + | |
| 47 | +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | |
| 48 | +watch( | |
| 49 | + () => appStore.getIsDark, | |
| 50 | + () => { | |
| 51 | + if (appStore.getIsDark == true) { | |
| 52 | + import('./style/dark.scss') | |
| 53 | + } | |
| 54 | + if (appStore.getIsDark == false) { | |
| 55 | + import('./style/light.scss') | |
| 56 | + } | |
| 57 | + }, | |
| 58 | + { immediate: true } | |
| 59 | +) | |
| 60 | +const currentSize = computed(() => { | |
| 61 | + let resSize: SizeType = 'small' | |
| 62 | + const appsize = appStore.getCurrentSize | |
| 63 | + switch (appsize) { | |
| 64 | + case 'large': | |
| 65 | + resSize = 'medium' | |
| 66 | + break | |
| 67 | + case 'default': | |
| 68 | + resSize = 'small' | |
| 69 | + break | |
| 70 | + case 'small': | |
| 71 | + resSize = 'mini' | |
| 72 | + break | |
| 73 | + } | |
| 74 | + return resSize | |
| 75 | +}) | |
| 76 | + | |
| 77 | +const reload = () => { | |
| 78 | + const g = unref(xGrid) | |
| 79 | + if (!g) { | |
| 80 | + return | |
| 81 | + } | |
| 82 | + g.commitProxy('query') | |
| 83 | +} | |
| 84 | + | |
| 85 | +const getSearchData = () => { | |
| 86 | + const g = unref(xGrid) | |
| 87 | + if (!g) { | |
| 88 | + return | |
| 89 | + } | |
| 90 | + const queryParams = Object.assign({}, JSON.parse(JSON.stringify(g.getProxyInfo()?.form))) | |
| 91 | + return queryParams | |
| 92 | +} | |
| 93 | + | |
| 94 | +let proxyForm = false | |
| 95 | + | |
| 96 | +// columns | |
| 97 | +const getColumnsConfig = (options: XTableProps) => { | |
| 98 | + const { allSchemas } = options | |
| 99 | + if (!allSchemas) return | |
| 100 | + if (allSchemas.printSchema) { | |
| 101 | + options.printConfig = { | |
| 102 | + columns: allSchemas.printSchema | |
| 103 | + } | |
| 104 | + } | |
| 105 | + if (allSchemas.formSchema) { | |
| 106 | + proxyForm = true | |
| 107 | + options.formConfig = { | |
| 108 | + enabled: true, | |
| 109 | + titleWidth: 100, | |
| 110 | + titleAlign: 'right', | |
| 111 | + items: allSchemas.searchSchema | |
| 112 | + } | |
| 113 | + } | |
| 114 | + if (allSchemas.tableSchema) { | |
| 115 | + options.columns = allSchemas.tableSchema | |
| 116 | + } | |
| 117 | +} | |
| 118 | + | |
| 119 | +// 动态请求 | |
| 120 | +const getProxyConfig = (options: XTableProps) => { | |
| 121 | + const { getListApi, proxyConfig, data } = options | |
| 122 | + if (proxyConfig || data) return | |
| 123 | + if (getListApi && isFunction(getListApi)) { | |
| 124 | + options.proxyConfig = { | |
| 125 | + seq: true, // 启用动态序号代理(分页之后索引自动计算为当前页的起始序号) | |
| 126 | + form: proxyForm, // 启用表单代理,当点击表单提交按钮时会自动触发 reload 行为 | |
| 127 | + props: { result: 'list', total: 'total' }, | |
| 128 | + ajax: { | |
| 129 | + query: async ({ page, form }) => { | |
| 130 | + let queryParams: any = Object.assign({}, JSON.parse(JSON.stringify(form))) | |
| 131 | + if (options.params) { | |
| 132 | + queryParams = Object.assign(queryParams, options.params) | |
| 133 | + } | |
| 134 | + queryParams.pageSize = page.currentPage | |
| 135 | + queryParams.page = page.pageSize | |
| 136 | + | |
| 137 | + return new Promise(async (resolve) => { | |
| 138 | + resolve(await getListApi(queryParams)) | |
| 139 | + }) | |
| 140 | + } | |
| 141 | + } | |
| 142 | + } | |
| 143 | + } | |
| 144 | +} | |
| 145 | + | |
| 146 | +// 分页 | |
| 147 | +const getPageConfig = (options: XTableProps) => { | |
| 148 | + const { pagination, pagerConfig } = options | |
| 149 | + if (pagerConfig) return | |
| 150 | + if (pagination) { | |
| 151 | + if (isBoolean(pagination)) { | |
| 152 | + options.pagerConfig = { | |
| 153 | + border: false, // 带边框 | |
| 154 | + background: true, // 带背景颜色 | |
| 155 | + perfect: false, // 配套的样式 | |
| 156 | + pageSize: 10, // 每页大小 | |
| 157 | + pagerCount: 7, // 显示页码按钮的数量 | |
| 158 | + autoHidden: false, // 当只有一页时自动隐藏 | |
| 159 | + pageSizes: [5, 10, 20, 30, 50, 100], // 每页大小选项列表 | |
| 160 | + layouts: [ | |
| 161 | + 'PrevJump', | |
| 162 | + 'PrevPage', | |
| 163 | + 'JumpNumber', | |
| 164 | + 'NextPage', | |
| 165 | + 'NextJump', | |
| 166 | + 'Sizes', | |
| 167 | + 'FullJump', | |
| 168 | + 'Total' | |
| 169 | + ] | |
| 170 | + } | |
| 171 | + return | |
| 172 | + } | |
| 173 | + options.pagerConfig = pagination | |
| 174 | + } | |
| 175 | +} | |
| 176 | + | |
| 177 | +// tool bar | |
| 178 | +const getToolBarConfig = (options: XTableProps) => { | |
| 179 | + const { toolBar, toolbarConfig } = options | |
| 180 | + if (toolbarConfig) return | |
| 181 | + if (toolBar) { | |
| 182 | + if (!isBoolean(toolBar)) { | |
| 183 | + options.toolbarConfig = toolBar | |
| 184 | + return | |
| 185 | + } | |
| 186 | + } else { | |
| 187 | + options.toolbarConfig = { | |
| 188 | + slots: { buttons: 'toolbar_buttons' } | |
| 189 | + } | |
| 190 | + } | |
| 191 | +} | |
| 192 | + | |
| 193 | +const setProps = (prop: Partial<XTableProps>) => { | |
| 194 | + innerProps.value = { ...unref(innerProps), ...prop } | |
| 195 | +} | |
| 196 | + | |
| 197 | +defineExpose({ reload, Ref: xGrid, getSearchData }) | |
| 198 | +emit('register', { reload, getSearchData, setProps }) | |
| 199 | +</script> | |
| 200 | +<style lang="scss"> | |
| 201 | +@import './style/index.scss'; | |
| 202 | +</style> | ... | ... |
yudao-ui-admin-vue3/src/components/XTable/src/style/dark.scss
0 → 100644
| 1 | +// 修改样式变量 | |
| 2 | +//@import 'vxe-table/styles/variable.scss'; | |
| 3 | + | |
| 4 | +/*font*/ | |
| 5 | +$vxe-font-color: #e5e7eb; | |
| 6 | +// $vxe-font-size: 14px !default; | |
| 7 | +// $vxe-font-size-medium: 16px !default; | |
| 8 | +// $vxe-font-size-small: 14px !default; | |
| 9 | +// $vxe-font-size-mini: 12px !default; | |
| 10 | + | |
| 11 | +/*color*/ | |
| 12 | +$vxe-primary-color: #409eff !default; | |
| 13 | +$vxe-success-color: #67c23a !default; | |
| 14 | +$vxe-info-color: #909399 !default; | |
| 15 | +$vxe-warning-color: #e6a23c !default; | |
| 16 | +$vxe-danger-color: #f56c6c !default; | |
| 17 | +$vxe-disabled-color: #bfbfbf !default; | |
| 18 | +$vxe-primary-disabled-color: #c0c4cc !default; | |
| 19 | + | |
| 20 | +/*loading*/ | |
| 21 | +$vxe-loading-color: $vxe-primary-color !default; | |
| 22 | +$vxe-loading-background-color: #1d1e1f !default; | |
| 23 | +$vxe-loading-z-index: 999 !default; | |
| 24 | + | |
| 25 | +/*icon*/ | |
| 26 | +$vxe-icon-font-family: Verdana, Arial, Tahoma !default; | |
| 27 | +$vxe-icon-background-color: #e5e7eb !default; | |
| 28 | + | |
| 29 | +/*toolbar*/ | |
| 30 | +$vxe-toolbar-background-color: #1d1e1f !default; | |
| 31 | +$vxe-toolbar-button-border: #dcdfe6 !default; | |
| 32 | +$vxe-toolbar-custom-active-background-color: #d9dadb !default; | |
| 33 | +$vxe-toolbar-panel-background-color: #e5e7eb !default; | |
| 34 | + | |
| 35 | +$vxe-table-font-color: #e5e7eb; | |
| 36 | +$vxe-table-header-background-color: #1d1e1f; | |
| 37 | +$vxe-table-body-background-color: #141414; | |
| 38 | +$vxe-table-row-striped-background-color: #1d1d1d; | |
| 39 | +$vxe-table-row-hover-background-color: #1d1e1f; | |
| 40 | +$vxe-table-row-hover-striped-background-color: #1e1e1e; | |
| 41 | +$vxe-table-footer-background-color: #1d1e1f; | |
| 42 | +$vxe-table-row-current-background-color: #302d2d; | |
| 43 | +$vxe-table-column-current-background-color: #302d2d; | |
| 44 | +$vxe-table-column-hover-background-color: #302d2d; | |
| 45 | +$vxe-table-row-hover-current-background-color: #302d2d; | |
| 46 | +$vxe-table-row-checkbox-checked-background-color: #3e3c37 !default; | |
| 47 | +$vxe-table-row-hover-checkbox-checked-background-color: #615a4a !default; | |
| 48 | +$vxe-table-menu-background-color: #1d1e1f; | |
| 49 | +$vxe-table-border-width: 1px !default; | |
| 50 | +$vxe-table-border-color: #4c4d4f !default; | |
| 51 | +$vxe-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px rgba(0, 0, 0, 0.12) !default; | |
| 52 | +$vxe-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px rgba(0, 0, 0, 0.12) !default; | |
| 53 | + | |
| 54 | +$vxe-form-background-color: #141414; | |
| 55 | + | |
| 56 | +/*pager*/ | |
| 57 | +$vxe-pager-background-color: #1d1e1f !default; | |
| 58 | +$vxe-pager-perfect-background-color: #262727 !default; | |
| 59 | +$vxe-pager-perfect-button-background-color: #a7a3a3 !default; | |
| 60 | + | |
| 61 | +$vxe-input-background-color: #141414; | |
| 62 | +$vxe-input-border-color: #4c4d4f !default; | |
| 63 | + | |
| 64 | +$vxe-select-option-hover-background-color: #262626 !default; | |
| 65 | +$vxe-select-panel-background-color: #141414 !default; | |
| 66 | +$vxe-select-empty-color: #262626 !default; | |
| 67 | +$vxe-optgroup-title-color: #909399 !default; | |
| 68 | + | |
| 69 | +/*button*/ | |
| 70 | +$vxe-button-default-background-color: #262626; | |
| 71 | +$vxe-button-dropdown-panel-background-color: #141414; | |
| 72 | + | |
| 73 | +/*modal*/ | |
| 74 | +$vxe-modal-header-background-color: #141414; | |
| 75 | +$vxe-modal-body-background-color: #141414; | |
| 76 | +$vxe-modal-border-color: #3b3b3b; | |
| 77 | + | |
| 78 | +/*pulldown*/ | |
| 79 | +$vxe-pulldown-panel-background-color: #262626 !default; | |
| 80 | + | |
| 81 | +@import 'vxe-table/styles/index'; | ... | ... |
yudao-ui-admin-vue3/src/components/XTable/src/style/index.scss
0 → 100644
yudao-ui-admin-vue3/src/components/XTable/src/style/light.scss
0 → 100644
| 1 | +// 修改样式变量 | |
| 2 | +// /*font*/ | |
| 3 | +// $vxe-font-size: 12px !default; | |
| 4 | +// $vxe-font-size-medium: 16px !default; | |
| 5 | +// $vxe-font-size-small: 14px !default; | |
| 6 | +// $vxe-font-size-mini: 12px !default; | |
| 7 | +/*color*/ | |
| 8 | +$vxe-primary-color: #409eff !default; | |
| 9 | +$vxe-success-color: #67c23a !default; | |
| 10 | +$vxe-info-color: #909399 !default; | |
| 11 | +$vxe-warning-color: #e6a23c !default; | |
| 12 | +$vxe-danger-color: #f56c6c !default; | |
| 13 | +$vxe-disabled-color: #bfbfbf !default; | |
| 14 | +$vxe-primary-disabled-color: #c0c4cc !default; | |
| 15 | + | |
| 16 | +@import 'vxe-table/styles/index.scss'; | ... | ... |
yudao-ui-admin-vue3/src/components/XTable/src/type.ts
0 → 100644
| 1 | +import { CrudSchema } from '@/hooks/web/useCrudSchemas' | |
| 2 | +import type { VxeGridProps, VxeGridPropTypes } from 'vxe-table' | |
| 3 | + | |
| 4 | +export type XTableProps<D = any> = VxeGridProps<D> & { | |
| 5 | + allSchemas?: CrudSchema | |
| 6 | + getListApi?: Function | |
| 7 | + deleteApi?: Function | |
| 8 | + exportListApi?: Function | |
| 9 | + params?: any | |
| 10 | + pagination?: boolean | VxeGridPropTypes.PagerConfig | |
| 11 | + toolBar?: boolean | VxeGridPropTypes.ToolbarConfig | |
| 12 | + afterFetch?: Function | |
| 13 | +} | |
| 14 | +export type XColumns = VxeGridPropTypes.Columns | |
| 15 | + | |
| 16 | +export type VxeTableColumn = { | |
| 17 | + field: string | |
| 18 | + title?: string | |
| 19 | + children?: VxeTableColumn[] | |
| 20 | +} & Recordable | ... | ... |
yudao-ui-admin-vue3/src/components/index.ts
| ... | ... | @@ -4,6 +4,7 @@ import { Form } from '@/components/Form' |
| 4 | 4 | import { Table } from '@/components/Table' |
| 5 | 5 | import { Search } from '@/components/Search' |
| 6 | 6 | import { XModal } from '@/components/XModal' |
| 7 | +import { XTable } from '@/components/XTable' | |
| 7 | 8 | import { XButton, XTextButton } from '@/components/XButton' |
| 8 | 9 | import { DictTag } from '@/components/DictTag' |
| 9 | 10 | import { ContentWrap } from '@/components/ContentWrap' |
| ... | ... | @@ -15,6 +16,7 @@ export const setupGlobCom = (app: App<Element>): void => { |
| 15 | 16 | app.component('Table', Table) |
| 16 | 17 | app.component('Search', Search) |
| 17 | 18 | app.component('XModal', XModal) |
| 19 | + app.component('XTable', XTable) | |
| 18 | 20 | app.component('XButton', XButton) |
| 19 | 21 | app.component('XTextButton', XTextButton) |
| 20 | 22 | app.component('DictTag', DictTag) | ... | ... |
yudao-ui-admin-vue3/src/hooks/web/useXTable.ts
0 → 100644
| 1 | +import { ref, unref } from 'vue' | |
| 2 | +import { XTableProps } from '@/components/XTable/src/type' | |
| 3 | + | |
| 4 | +export interface tableMethod { | |
| 5 | + reload: () => void | |
| 6 | + setProps: (props: XTableProps) => void | |
| 7 | +} | |
| 8 | + | |
| 9 | +export function useXTable(props: XTableProps): [Function, tableMethod] { | |
| 10 | + const tableRef = ref<Nullable<tableMethod>>(null) | |
| 11 | + | |
| 12 | + function register(instance) { | |
| 13 | + tableRef.value = instance | |
| 14 | + props && instance.setProps(props) | |
| 15 | + } | |
| 16 | + function getInstance(): tableMethod { | |
| 17 | + const table = unref(tableRef) | |
| 18 | + if (!table) { | |
| 19 | + console.error('表格实例不存在') | |
| 20 | + } | |
| 21 | + return table as tableMethod | |
| 22 | + } | |
| 23 | + const methods: tableMethod = { | |
| 24 | + reload: () => getInstance().reload(), | |
| 25 | + setProps: (props) => getInstance().setProps(props) | |
| 26 | + } | |
| 27 | + return [register, methods] | |
| 28 | +} | ... | ... |