mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	feat: 封装xTable 组件
This commit is contained in:
		
							
								
								
									
										3
									
								
								yudao-ui-admin-vue3/src/components/XTable/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								yudao-ui-admin-vue3/src/components/XTable/index.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | import XTable from './src/XTable.vue' | ||||||
|  |  | ||||||
|  | export { XTable } | ||||||
							
								
								
									
										202
									
								
								yudao-ui-admin-vue3/src/components/XTable/src/XTable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								yudao-ui-admin-vue3/src/components/XTable/src/XTable.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,202 @@ | |||||||
|  | <template> | ||||||
|  |   <VxeGrid v-bind="getProps" ref="xGrid" :class="`${prefixCls}`" class="xtable-scrollbar"> | ||||||
|  |     <template #[item]="data" v-for="item in Object.keys($slots)" :key="item"> | ||||||
|  |       <slot :name="item" v-bind="data || {}"></slot> | ||||||
|  |     </template> | ||||||
|  |   </VxeGrid> | ||||||
|  | </template> | ||||||
|  | <script lang="ts" setup name="XTable"> | ||||||
|  | import { computed, PropType, ref, unref, useAttrs, watch } from 'vue' | ||||||
|  | import { SizeType, VxeGridInstance } from 'vxe-table' | ||||||
|  | import { useAppStore } from '@/store/modules/app' | ||||||
|  | import { useDesign } from '@/hooks/web/useDesign' | ||||||
|  | import { XTableProps } from './type' | ||||||
|  | import { isBoolean, isFunction } from '@/utils/is' | ||||||
|  |  | ||||||
|  | const appStore = useAppStore() | ||||||
|  |  | ||||||
|  | const { getPrefixCls } = useDesign() | ||||||
|  | const prefixCls = getPrefixCls('x-vxe-table') | ||||||
|  |  | ||||||
|  | const attrs = useAttrs() | ||||||
|  | const emit = defineEmits(['register']) | ||||||
|  |  | ||||||
|  | const props = defineProps({ | ||||||
|  |   options: { | ||||||
|  |     type: Object as PropType<XTableProps>, | ||||||
|  |     default: () => {} | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  | const innerProps = ref<Partial<XTableProps>>() | ||||||
|  |  | ||||||
|  | const getProps = computed(() => { | ||||||
|  |   const options = innerProps.value || props.options | ||||||
|  |   options.size = currentSize as any | ||||||
|  |   options.height = 700 | ||||||
|  |   getColumnsConfig(options) | ||||||
|  |   getProxyConfig(options) | ||||||
|  |   getPageConfig(options) | ||||||
|  |   getToolBarConfig(options) | ||||||
|  |   // console.log(options); | ||||||
|  |   return { | ||||||
|  |     ...options, | ||||||
|  |     ...attrs | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | ||||||
|  | watch( | ||||||
|  |   () => appStore.getIsDark, | ||||||
|  |   () => { | ||||||
|  |     if (appStore.getIsDark == true) { | ||||||
|  |       import('./style/dark.scss') | ||||||
|  |     } | ||||||
|  |     if (appStore.getIsDark == false) { | ||||||
|  |       import('./style/light.scss') | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   { immediate: true } | ||||||
|  | ) | ||||||
|  | const currentSize = computed(() => { | ||||||
|  |   let resSize: SizeType = 'small' | ||||||
|  |   const appsize = appStore.getCurrentSize | ||||||
|  |   switch (appsize) { | ||||||
|  |     case 'large': | ||||||
|  |       resSize = 'medium' | ||||||
|  |       break | ||||||
|  |     case 'default': | ||||||
|  |       resSize = 'small' | ||||||
|  |       break | ||||||
|  |     case 'small': | ||||||
|  |       resSize = 'mini' | ||||||
|  |       break | ||||||
|  |   } | ||||||
|  |   return resSize | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | const reload = () => { | ||||||
|  |   const g = unref(xGrid) | ||||||
|  |   if (!g) { | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  |   g.commitProxy('query') | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const getSearchData = () => { | ||||||
|  |   const g = unref(xGrid) | ||||||
|  |   if (!g) { | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  |   const queryParams = Object.assign({}, JSON.parse(JSON.stringify(g.getProxyInfo()?.form))) | ||||||
|  |   return queryParams | ||||||
|  | } | ||||||
|  |  | ||||||
|  | let proxyForm = false | ||||||
|  |  | ||||||
|  | // columns | ||||||
|  | const getColumnsConfig = (options: XTableProps) => { | ||||||
|  |   const { allSchemas } = options | ||||||
|  |   if (!allSchemas) return | ||||||
|  |   if (allSchemas.printSchema) { | ||||||
|  |     options.printConfig = { | ||||||
|  |       columns: allSchemas.printSchema | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (allSchemas.formSchema) { | ||||||
|  |     proxyForm = true | ||||||
|  |     options.formConfig = { | ||||||
|  |       enabled: true, | ||||||
|  |       titleWidth: 100, | ||||||
|  |       titleAlign: 'right', | ||||||
|  |       items: allSchemas.searchSchema | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (allSchemas.tableSchema) { | ||||||
|  |     options.columns = allSchemas.tableSchema | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 动态请求 | ||||||
|  | const getProxyConfig = (options: XTableProps) => { | ||||||
|  |   const { getListApi, proxyConfig, data } = options | ||||||
|  |   if (proxyConfig || data) return | ||||||
|  |   if (getListApi && isFunction(getListApi)) { | ||||||
|  |     options.proxyConfig = { | ||||||
|  |       seq: true, // 启用动态序号代理(分页之后索引自动计算为当前页的起始序号) | ||||||
|  |       form: proxyForm, // 启用表单代理,当点击表单提交按钮时会自动触发 reload 行为 | ||||||
|  |       props: { result: 'list', total: 'total' }, | ||||||
|  |       ajax: { | ||||||
|  |         query: async ({ page, form }) => { | ||||||
|  |           let queryParams: any = Object.assign({}, JSON.parse(JSON.stringify(form))) | ||||||
|  |           if (options.params) { | ||||||
|  |             queryParams = Object.assign(queryParams, options.params) | ||||||
|  |           } | ||||||
|  |           queryParams.pageSize = page.currentPage | ||||||
|  |           queryParams.page = page.pageSize | ||||||
|  |  | ||||||
|  |           return new Promise(async (resolve) => { | ||||||
|  |             resolve(await getListApi(queryParams)) | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 分页 | ||||||
|  | const getPageConfig = (options: XTableProps) => { | ||||||
|  |   const { pagination, pagerConfig } = options | ||||||
|  |   if (pagerConfig) return | ||||||
|  |   if (pagination) { | ||||||
|  |     if (isBoolean(pagination)) { | ||||||
|  |       options.pagerConfig = { | ||||||
|  |         border: false, // 带边框 | ||||||
|  |         background: true, // 带背景颜色 | ||||||
|  |         perfect: false, // 配套的样式 | ||||||
|  |         pageSize: 10, // 每页大小 | ||||||
|  |         pagerCount: 7, // 显示页码按钮的数量 | ||||||
|  |         autoHidden: false, // 当只有一页时自动隐藏 | ||||||
|  |         pageSizes: [5, 10, 20, 30, 50, 100], // 每页大小选项列表 | ||||||
|  |         layouts: [ | ||||||
|  |           'PrevJump', | ||||||
|  |           'PrevPage', | ||||||
|  |           'JumpNumber', | ||||||
|  |           'NextPage', | ||||||
|  |           'NextJump', | ||||||
|  |           'Sizes', | ||||||
|  |           'FullJump', | ||||||
|  |           'Total' | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |     options.pagerConfig = pagination | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // tool bar | ||||||
|  | const getToolBarConfig = (options: XTableProps) => { | ||||||
|  |   const { toolBar, toolbarConfig } = options | ||||||
|  |   if (toolbarConfig) return | ||||||
|  |   if (toolBar) { | ||||||
|  |     if (!isBoolean(toolBar)) { | ||||||
|  |       options.toolbarConfig = toolBar | ||||||
|  |       return | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     options.toolbarConfig = { | ||||||
|  |       slots: { buttons: 'toolbar_buttons' } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const setProps = (prop: Partial<XTableProps>) => { | ||||||
|  |   innerProps.value = { ...unref(innerProps), ...prop } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | defineExpose({ reload, Ref: xGrid, getSearchData }) | ||||||
|  | emit('register', { reload, getSearchData, setProps }) | ||||||
|  | </script> | ||||||
|  | <style lang="scss"> | ||||||
|  | @import './style/index.scss'; | ||||||
|  | </style> | ||||||
| @ -0,0 +1,81 @@ | |||||||
|  | // 修改样式变量 | ||||||
|  | //@import 'vxe-table/styles/variable.scss'; | ||||||
|  |  | ||||||
|  | /*font*/ | ||||||
|  | $vxe-font-color: #e5e7eb; | ||||||
|  | // $vxe-font-size: 14px !default; | ||||||
|  | // $vxe-font-size-medium: 16px !default; | ||||||
|  | // $vxe-font-size-small: 14px !default; | ||||||
|  | // $vxe-font-size-mini: 12px !default; | ||||||
|  |  | ||||||
|  | /*color*/ | ||||||
|  | $vxe-primary-color: #409eff !default; | ||||||
|  | $vxe-success-color: #67c23a !default; | ||||||
|  | $vxe-info-color: #909399 !default; | ||||||
|  | $vxe-warning-color: #e6a23c !default; | ||||||
|  | $vxe-danger-color: #f56c6c !default; | ||||||
|  | $vxe-disabled-color: #bfbfbf !default; | ||||||
|  | $vxe-primary-disabled-color: #c0c4cc !default; | ||||||
|  |  | ||||||
|  | /*loading*/ | ||||||
|  | $vxe-loading-color: $vxe-primary-color !default; | ||||||
|  | $vxe-loading-background-color: #1d1e1f !default; | ||||||
|  | $vxe-loading-z-index: 999 !default; | ||||||
|  |  | ||||||
|  | /*icon*/ | ||||||
|  | $vxe-icon-font-family: Verdana, Arial, Tahoma !default; | ||||||
|  | $vxe-icon-background-color: #e5e7eb !default; | ||||||
|  |  | ||||||
|  | /*toolbar*/ | ||||||
|  | $vxe-toolbar-background-color: #1d1e1f !default; | ||||||
|  | $vxe-toolbar-button-border: #dcdfe6 !default; | ||||||
|  | $vxe-toolbar-custom-active-background-color: #d9dadb !default; | ||||||
|  | $vxe-toolbar-panel-background-color: #e5e7eb !default; | ||||||
|  |  | ||||||
|  | $vxe-table-font-color: #e5e7eb; | ||||||
|  | $vxe-table-header-background-color: #1d1e1f; | ||||||
|  | $vxe-table-body-background-color: #141414; | ||||||
|  | $vxe-table-row-striped-background-color: #1d1d1d; | ||||||
|  | $vxe-table-row-hover-background-color: #1d1e1f; | ||||||
|  | $vxe-table-row-hover-striped-background-color: #1e1e1e; | ||||||
|  | $vxe-table-footer-background-color: #1d1e1f; | ||||||
|  | $vxe-table-row-current-background-color: #302d2d; | ||||||
|  | $vxe-table-column-current-background-color: #302d2d; | ||||||
|  | $vxe-table-column-hover-background-color: #302d2d; | ||||||
|  | $vxe-table-row-hover-current-background-color: #302d2d; | ||||||
|  | $vxe-table-row-checkbox-checked-background-color: #3e3c37 !default; | ||||||
|  | $vxe-table-row-hover-checkbox-checked-background-color: #615a4a !default; | ||||||
|  | $vxe-table-menu-background-color: #1d1e1f; | ||||||
|  | $vxe-table-border-width: 1px !default; | ||||||
|  | $vxe-table-border-color: #4c4d4f !default; | ||||||
|  | $vxe-table-fixed-left-scrolling-box-shadow: 8px 0px 10px -5px rgba(0, 0, 0, 0.12) !default; | ||||||
|  | $vxe-table-fixed-right-scrolling-box-shadow: -8px 0px 10px -5px rgba(0, 0, 0, 0.12) !default; | ||||||
|  |  | ||||||
|  | $vxe-form-background-color: #141414; | ||||||
|  |  | ||||||
|  | /*pager*/ | ||||||
|  | $vxe-pager-background-color: #1d1e1f !default; | ||||||
|  | $vxe-pager-perfect-background-color: #262727 !default; | ||||||
|  | $vxe-pager-perfect-button-background-color: #a7a3a3 !default; | ||||||
|  |  | ||||||
|  | $vxe-input-background-color: #141414; | ||||||
|  | $vxe-input-border-color: #4c4d4f !default; | ||||||
|  |  | ||||||
|  | $vxe-select-option-hover-background-color: #262626 !default; | ||||||
|  | $vxe-select-panel-background-color: #141414 !default; | ||||||
|  | $vxe-select-empty-color: #262626 !default; | ||||||
|  | $vxe-optgroup-title-color: #909399 !default; | ||||||
|  |  | ||||||
|  | /*button*/ | ||||||
|  | $vxe-button-default-background-color: #262626; | ||||||
|  | $vxe-button-dropdown-panel-background-color: #141414; | ||||||
|  |  | ||||||
|  | /*modal*/ | ||||||
|  | $vxe-modal-header-background-color: #141414; | ||||||
|  | $vxe-modal-body-background-color: #141414; | ||||||
|  | $vxe-modal-border-color: #3b3b3b; | ||||||
|  |  | ||||||
|  | /*pulldown*/ | ||||||
|  | $vxe-pulldown-panel-background-color: #262626 !default; | ||||||
|  |  | ||||||
|  | @import 'vxe-table/styles/index'; | ||||||
| @ -0,0 +1,6 @@ | |||||||
|  | @import 'vxe-table/styles/variable.scss'; | ||||||
|  | @import 'vxe-table/styles/modules.scss'; | ||||||
|  | // @import './theme/light.scss'; | ||||||
|  | i { | ||||||
|  |   border-color: initial; | ||||||
|  | } | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | // 修改样式变量 | ||||||
|  | // /*font*/ | ||||||
|  | // $vxe-font-size: 12px !default; | ||||||
|  | // $vxe-font-size-medium: 16px !default; | ||||||
|  | // $vxe-font-size-small: 14px !default; | ||||||
|  | // $vxe-font-size-mini: 12px !default; | ||||||
|  | /*color*/ | ||||||
|  | $vxe-primary-color: #409eff !default; | ||||||
|  | $vxe-success-color: #67c23a !default; | ||||||
|  | $vxe-info-color: #909399 !default; | ||||||
|  | $vxe-warning-color: #e6a23c !default; | ||||||
|  | $vxe-danger-color: #f56c6c !default; | ||||||
|  | $vxe-disabled-color: #bfbfbf !default; | ||||||
|  | $vxe-primary-disabled-color: #c0c4cc !default; | ||||||
|  |  | ||||||
|  | @import 'vxe-table/styles/index.scss'; | ||||||
							
								
								
									
										20
									
								
								yudao-ui-admin-vue3/src/components/XTable/src/type.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								yudao-ui-admin-vue3/src/components/XTable/src/type.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | import { CrudSchema } from '@/hooks/web/useCrudSchemas' | ||||||
|  | import type { VxeGridProps, VxeGridPropTypes } from 'vxe-table' | ||||||
|  |  | ||||||
|  | export type XTableProps<D = any> = VxeGridProps<D> & { | ||||||
|  |   allSchemas?: CrudSchema | ||||||
|  |   getListApi?: Function | ||||||
|  |   deleteApi?: Function | ||||||
|  |   exportListApi?: Function | ||||||
|  |   params?: any | ||||||
|  |   pagination?: boolean | VxeGridPropTypes.PagerConfig | ||||||
|  |   toolBar?: boolean | VxeGridPropTypes.ToolbarConfig | ||||||
|  |   afterFetch?: Function | ||||||
|  | } | ||||||
|  | export type XColumns = VxeGridPropTypes.Columns | ||||||
|  |  | ||||||
|  | export type VxeTableColumn = { | ||||||
|  |   field: string | ||||||
|  |   title?: string | ||||||
|  |   children?: VxeTableColumn[] | ||||||
|  | } & Recordable | ||||||
| @ -4,6 +4,7 @@ import { Form } from '@/components/Form' | |||||||
| import { Table } from '@/components/Table' | import { Table } from '@/components/Table' | ||||||
| import { Search } from '@/components/Search' | import { Search } from '@/components/Search' | ||||||
| import { XModal } from '@/components/XModal' | import { XModal } from '@/components/XModal' | ||||||
|  | import { XTable } from '@/components/XTable' | ||||||
| import { XButton, XTextButton } from '@/components/XButton' | import { XButton, XTextButton } from '@/components/XButton' | ||||||
| import { DictTag } from '@/components/DictTag' | import { DictTag } from '@/components/DictTag' | ||||||
| import { ContentWrap } from '@/components/ContentWrap' | import { ContentWrap } from '@/components/ContentWrap' | ||||||
| @ -15,6 +16,7 @@ export const setupGlobCom = (app: App<Element>): void => { | |||||||
|   app.component('Table', Table) |   app.component('Table', Table) | ||||||
|   app.component('Search', Search) |   app.component('Search', Search) | ||||||
|   app.component('XModal', XModal) |   app.component('XModal', XModal) | ||||||
|  |   app.component('XTable', XTable) | ||||||
|   app.component('XButton', XButton) |   app.component('XButton', XButton) | ||||||
|   app.component('XTextButton', XTextButton) |   app.component('XTextButton', XTextButton) | ||||||
|   app.component('DictTag', DictTag) |   app.component('DictTag', DictTag) | ||||||
|  | |||||||
							
								
								
									
										28
									
								
								yudao-ui-admin-vue3/src/hooks/web/useXTable.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								yudao-ui-admin-vue3/src/hooks/web/useXTable.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | import { ref, unref } from 'vue' | ||||||
|  | import { XTableProps } from '@/components/XTable/src/type' | ||||||
|  |  | ||||||
|  | export interface tableMethod { | ||||||
|  |   reload: () => void | ||||||
|  |   setProps: (props: XTableProps) => void | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function useXTable(props: XTableProps): [Function, tableMethod] { | ||||||
|  |   const tableRef = ref<Nullable<tableMethod>>(null) | ||||||
|  |  | ||||||
|  |   function register(instance) { | ||||||
|  |     tableRef.value = instance | ||||||
|  |     props && instance.setProps(props) | ||||||
|  |   } | ||||||
|  |   function getInstance(): tableMethod { | ||||||
|  |     const table = unref(tableRef) | ||||||
|  |     if (!table) { | ||||||
|  |       console.error('表格实例不存在') | ||||||
|  |     } | ||||||
|  |     return table as tableMethod | ||||||
|  |   } | ||||||
|  |   const methods: tableMethod = { | ||||||
|  |     reload: () => getInstance().reload(), | ||||||
|  |     setProps: (props) => getInstance().setProps(props) | ||||||
|  |   } | ||||||
|  |   return [register, methods] | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 xingyu
					xingyu