diff --git a/components.d.ts b/components.d.ts index f0d011ba..ec16f58f 100644 --- a/components.d.ts +++ b/components.d.ts @@ -30,6 +30,7 @@ declare module '@vue/runtime-core' { ARow: typeof import('ant-design-vue/es')['Row'] ASelect: typeof import('ant-design-vue/es')['Select'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] + ASpace: typeof import('ant-design-vue/es')['Space'] ASpin: typeof import('ant-design-vue/es')['Spin'] ASwitch: typeof import('ant-design-vue/es')['Switch'] ATable: typeof import('ant-design-vue/es')['Table'] diff --git a/package.json b/package.json index 896ac93a..26e555d8 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "typescript": "^4.9.3", "vite": "^4.0.0", "vite-plugin-html": "^3.2.0", + "vite-plugin-style-import": "^2.0.0", "vite-plugin-vue-setup-extend": "^0.4.0", "vue-tsc": "^1.0.11" }, diff --git a/src/components/Table/index.module.less b/src/components/Table/index.module.less new file mode 100644 index 00000000..a0e94e07 --- /dev/null +++ b/src/components/Table/index.module.less @@ -0,0 +1,52 @@ +.jtable-body { + width: 100%; + padding: 0 24px 24px; + background-color: white; + .jtable-body-header { + padding: 16px 0; + display: flex; + justify-content: space-between; + align-items: center; + .jtable-body-header-right { + display: flex; + gap: 8px; + .jtable-setting-item { + color: rgba(0, 0, 0, 0.75); + font-size: 16px; + cursor: pointer; + + &:hover { + color: @primary-color-hover; + } + + &.active { + color: @primary-color-active; + } + } + } + } + .jtable-content { + .jtable-alert { + margin-bottom: 16px; + } + .jtable-card { + .jtable-card-items { + display: grid; + grid-gap: 26px; + .jtable-card-item { + display: flex; + } + } + } + } + .jtable-pagination { + margin-top: 20px; + display: flex; + justify-content: flex-end; + :global { + .ant-pagination-item { + display: none !important; + } + } + } +} \ No newline at end of file diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx new file mode 100644 index 00000000..38e2e6af --- /dev/null +++ b/src/components/Table/index.tsx @@ -0,0 +1,268 @@ +import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue' +import styles from './index.module.less' +import { Pagination, Table, Empty, Spin, Alert } from 'ant-design-vue' +import type { TableProps, ColumnProps } from 'ant-design-vue/es/table' +import type { TooltipProps } from 'ant-design-vue/es/tooltip' +import type { PopconfirmProps } from 'ant-design-vue/es/popconfirm' +import { CSSProperties, PropType } from 'vue'; + +enum ModelEnum { + TABLE = 'TABLE', + CARD = 'CARD', +} + +type RequestData = { + code: string; + result: { + data: Record[] | undefined; + pageIndex: number; + pageSize: number; + total: number; + }; + status: number; +} & Record; + +export interface ActionsType { + key: string; + text?: string; + disabled?: boolean; + permission?: boolean; + onClick?: (data: any) => void; + style?: CSSProperties; + tooltip?: TooltipProps; + popConfirm?: PopconfirmProps; + icon?: string; +} + +export interface JColumnProps extends ColumnProps{ + scopedSlots?: boolean; // 是否为插槽 true: 是 false: 否 +} + +export interface JTableProps extends TableProps{ + request?: (params: Record & { + pageSize: number; + pageIndex: number; + }) => Promise>; + cardBodyClass?: string; + columns: JColumnProps[]; + params?: Record & { + pageSize: number; + pageIndex: number; + }; + model?: keyof typeof ModelEnum | undefined; // 显示table还是card + actions?: ActionsType[]; + noPagination?: boolean; + rowSelection?: TableProps['rowSelection']; + cardProps?: Record; + dataSource?: Record[]; +} + +const JTable = defineComponent({ + name: 'JTable', + slots: [ + 'headerTitle', // 顶部左边插槽 + 'card', // 卡片内容 + ], + emits: [ + 'modelChange', // 切换卡片和表格 + ], + props: { + request: { + type: Function, + default: undefined + }, + cardBodyClass: { + type: String, + default: '' + }, + columns: { + type: Array, + default: () => [] + }, + params: { + type: Object, + default: () => {} + }, + model: { + type: [String, undefined], + default: undefined + }, + actions: { + type: Array as PropType, + default: () => [] + }, + noPagination: { + type: Boolean, + default: false + }, + rowSelection: { + type: Object as PropType, + default: () => undefined + }, + cardProps: { + type: Object, + default: undefined + }, + dataSource: { + type: Array, + default: () => [] + } + } as any, + setup(props: JTableProps ,{ slots, emit }){ + const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE + const _model = ref(props.model ? props.model : ModelEnum.CARD); // 模式切换 + const column = ref(4); + const _dataSource = ref[]>([]) + const pageIndex = ref(0) + const pageSize = ref(6) + const total = ref(0) + const _columns = ref(props?.columns || []) + const loading = ref(true) + + // alert关闭,取消选择 + const handleAlertClose = () => { + emit('cancelSelect') + } + + /** + * 请求数据 + */ + const handleSearch = async (_params?: Record) => { + loading.value = true + if(props.request) { + const resp = await props.request({ + pageSize: 12, + pageIndex: 1, + ..._params + }) + if(resp.status === 200){ + // 判断如果是最后一页且最后一页为空,就跳转到前一页 + if(resp.result?.data?.length === 0 && resp.result.total && resp.result.pageSize && resp.result.pageIndex) { + handleSearch({ + ..._params, + pageSize: pageSize.value, + pageIndex: pageIndex.value - 1, + }) + } else { + _dataSource.value = resp.result?.data || [] + pageIndex.value = resp.result?.pageIndex || 0 + pageSize.value = resp.result?.pageSize || 6 + total.value = resp.result?.total || 0 + } + } + } else { + _dataSource.value = props?.dataSource || [] + } + + loading.value = false + } + + watchEffect(() => { + handleSearch(props.params) + }) + + return () => +
+
+
+ {/* 顶部左边插槽 */} + {slots.headerTitle && slots.headerTitle()} +
+
+
{ + _model.value = ModelEnum.CARD + }}> + +
+
{ + _model.value = ModelEnum.TABLE + }}> + +
+
+
+ {/* content */} +
+ { + props?.rowSelection && props?.rowSelection?.selectedRowKeys && props.rowSelection.selectedRowKeys?.length ? +
+ 取消选择} + /> +
: null + } + { + _model.value === ModelEnum.CARD ? +
+ { + _dataSource.value.length ? +
+ { + _dataSource.value.map(item => slots.card ? +
{slots.card({row: item, actions: props?.actions || []})}
+ : null) + } +
: +
+ } +
: +
+ ) => { + const {column, record} = dt; + if((column?.key || column?.dataIndex) && column?.scopedSlots && (slots?.[column?.dataIndex] || slots?.[column?.key])) { + const _key = column?.key || column?.dataIndex + return slots?.[_key]!({row: record, actions: props.actions}) + } else { + return record?.[column?.dataIndex] || '' + } + } + }} + /> + + } + + {/* 分页 */} + { + _dataSource.value.length && !props.noPagination && +
+ { + return `第 ${range[0]} - ${range[1]} 条/总共 ${total} 条` + }} + onChange={(page, size) => { + handleSearch({ + ...props.params, + pageSize: size, + pageIndex: pageSize.value === size ? page : 1, + }) + }} + /> +
+ } + + + } +}) + +export default JTable diff --git a/src/components/Table/index.vue b/src/components/Table/index.vue index d352dcc4..274d5d3b 100644 --- a/src/components/Table/index.vue +++ b/src/components/Table/index.vue @@ -79,7 +79,7 @@ -