feat: 表格插槽

This commit is contained in:
100011797 2023-01-11 14:33:17 +08:00
parent aab98f3ddf
commit e3c3e43b31
5 changed files with 186 additions and 95 deletions

14
components.d.ts vendored
View File

@ -7,29 +7,43 @@ export {}
declare module '@vue/runtime-core' { declare module '@vue/runtime-core' {
export interface GlobalComponents { export interface GlobalComponents {
AAlert: typeof import('ant-design-vue/es')['Alert']
ABadge: typeof import('ant-design-vue/es')['Badge']
AButton: typeof import('ant-design-vue/es')['Button'] AButton: typeof import('ant-design-vue/es')['Button']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup'] ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col'] ACol: typeof import('ant-design-vue/es')['Col']
ACollapse: typeof import('ant-design-vue/es')['Collapse'] ACollapse: typeof import('ant-design-vue/es')['Collapse']
ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel'] ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
ADivider: typeof import('ant-design-vue/es')['Divider']
AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form'] AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem'] AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input'] AInput: typeof import('ant-design-vue/es')['Input']
AInputNumber: typeof import('ant-design-vue/es')['InputNumber'] AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
AModal: typeof import('ant-design-vue/es')['Modal'] AModal: typeof import('ant-design-vue/es')['Modal']
APagination: typeof import('ant-design-vue/es')['Pagination']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
ARow: typeof import('ant-design-vue/es')['Row'] ARow: typeof import('ant-design-vue/es')['Row']
ASelect: typeof import('ant-design-vue/es')['Select'] ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASpace: typeof import('ant-design-vue/es')['Space']
ASpin: typeof import('ant-design-vue/es')['Spin'] ASpin: typeof import('ant-design-vue/es')['Spin']
ATable: typeof import('ant-design-vue/es')['Table']
ATooltip: typeof import('ant-design-vue/es')['Tooltip'] ATooltip: typeof import('ant-design-vue/es')['Tooltip']
AUpload: typeof import('ant-design-vue/es')['Upload'] AUpload: typeof import('ant-design-vue/es')['Upload']
BadgeStatus: typeof import('./src/components/BadgeStatus/index.vue')['default'] BadgeStatus: typeof import('./src/components/BadgeStatus/index.vue')['default']
CardBox: typeof import('./src/components/CardBox/index.vue')['default'] CardBox: typeof import('./src/components/CardBox/index.vue')['default']
FormFormBuilder: typeof import('./src/components/Form/FormBuilder.vue')['default']
GeoComponent: typeof import('./src/components/GeoComponent/index.vue')['default'] GeoComponent: typeof import('./src/components/GeoComponent/index.vue')['default']
MonacoEditor: typeof import('./src/components/MonacoEditor/index.vue')['default'] MonacoEditor: typeof import('./src/components/MonacoEditor/index.vue')['default']
PermissionButton: typeof import('./src/components/PermissionButton/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink'] RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView'] RouterView: typeof import('vue-router')['RouterView']
Table: typeof import('./src/components/Table/index.vue')['default']
TitleComponent: typeof import('./src/components/TitleComponent/index.vue')['default']
ValueItem: typeof import('./src/components/ValueItem/index.vue')['default'] ValueItem: typeof import('./src/components/ValueItem/index.vue')['default']
} }
} }

View File

@ -60,7 +60,7 @@
</div> </div>
<!-- 按钮 --> <!-- 按钮 -->
<slot name="botton-tool"> <slot name="bottom-tool">
<div v-if="showTool" class="card-tools"> <div v-if="showTool" class="card-tools">
<div <div
v-for="item in actions" v-for="item in actions"

View File

@ -1,4 +1,5 @@
<template> <template>
<a-spin :spinning="loading">
<div class="jtable-body"> <div class="jtable-body">
<div class="jtable-body-header"> <div class="jtable-body-header">
<div class="jtable-body-header-left"> <div class="jtable-body-header-left">
@ -14,18 +15,30 @@
</div> </div>
</div> </div>
<div class="jtable-content"> <div class="jtable-content">
<!-- <div class="jtable-alert">
<a-alert message="Info Text" type="info" />
</div> -->
<div v-if="_model === ModelEnum.CARD" class="jtable-card"> <div v-if="_model === ModelEnum.CARD" class="jtable-card">
<div <div
v-if="dataSource.length" v-if="_dataSource.length"
class="jtable-card-items" class="jtable-card-items"
:style="{gridTemplateColumns: `repeat(${column}, 1fr)`}" :style="{gridTemplateColumns: `repeat(${column}, 1fr)`}"
> >
<div <div
class="jtable-card-item" class="jtable-card-item"
v-for="(item, index) in dataSource" v-for="(item, index) in _dataSource"
:key="index" :key="index"
> >
<slot name="cardRender" :item="item" :index="index"></slot> <CardBox :actions="actions" v-bind="cardProps">
<template #img>
<slot name="img">
<img :src="getImage('/device-product.png')" />
</slot>
</template>
<template #content>
<slot name="cardContent" :item="item" :index="index"></slot>
</template>
</CardBox>
</div> </div>
</div> </div>
<div v-else> <div v-else>
@ -33,23 +46,30 @@
</div> </div>
</div> </div>
<div v-else> <div v-else>
<a-table {...props} :columns="[..._columns]" :dataSource="dataSource" :pagination="false" :scroll="{ x: 1366 }"> <a-table :rowSelection="rowSelection" :columns="[..._columns]" :dataSource="_dataSource" :pagination="false" :scroll="{ x: 1366 }">
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'"> <template v-if="column.key === 'action'">
<a-space> <a-space>
<a-tooltip v-for="i in actions" :key="i.key" {...i.tooltip}> <a-tooltip v-for="i in actions" :key="i.key" v-bind="i.tooltip">
<a-popconfirm v-if="i.popConfirm" {...i.popConfirm}> <a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
<a>{{i.text}}</a> <a>
{{i.text}}
</a>
</a-popconfirm> </a-popconfirm>
<a v-else @click="i.onClick && i.onClick(record)">{{i.text}}</a> <a v-else @click="i.onClick && i.onClick(record)">
{{i.text}}
</a>
</a-tooltip> </a-tooltip>
</a-space> </a-space>
</template> </template>
<template v-else-if="column.scopedSlots">
<slot :name="column.key" :row="record"></slot>
</template>
</template> </template>
</a-table> </a-table>
</div> </div>
</div> </div>
<div class="jtable-pagination" v-if="dataSource.length"> <div class="jtable-pagination" v-if="_dataSource.length && !noPagination">
<a-pagination <a-pagination
size="small" size="small"
:total="total" :total="total"
@ -63,6 +83,7 @@
/> />
</div> </div>
</div> </div>
</a-spin>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -72,6 +93,7 @@ import type { TooltipProps } from 'ant-design-vue/es/tooltip'
import type { PopconfirmProps } from 'ant-design-vue/es/popconfirm' import type { PopconfirmProps } from 'ant-design-vue/es/popconfirm'
import { Empty } from 'ant-design-vue' import { Empty } from 'ant-design-vue'
import { CSSProperties } from 'vue'; import { CSSProperties } from 'vue';
import { getImage } from '@/utils/comm';
enum ModelEnum { enum ModelEnum {
TABLE = 'TABLE', TABLE = 'TABLE',
@ -91,17 +113,18 @@ type RequestData = {
export interface ActionsType { export interface ActionsType {
key: string; key: string;
text: string; text?: string;
disabled?: boolean; disabled?: boolean;
permission: boolean; permission?: boolean;
onClick?: (data: any) => void; onClick?: (data: any) => void;
style?: CSSProperties; style?: CSSProperties;
tooltip?: TooltipProps; tooltip?: TooltipProps;
popConfirm: PopconfirmProps popConfirm?: PopconfirmProps;
icon?: string;
} }
interface JTableProps extends TableProps{ interface JTableProps extends TableProps{
request: (params: Record<string, any> & { request?: (params: Record<string, any> & {
pageSize: number; pageSize: number;
pageIndex: number; pageIndex: number;
}) => Promise<Partial<RequestData>>; }) => Promise<Partial<RequestData>>;
@ -112,10 +135,13 @@ interface JTableProps extends TableProps{
pageIndex: number; pageIndex: number;
}; };
model?: keyof typeof ModelEnum | undefined; // tablecard model?: keyof typeof ModelEnum | undefined; // tablecard
actions?: ActionsType[] actions?: ActionsType[];
noPagination?: boolean;
rowSelection?: TableProps['rowSelection'];
cardProps?: Record<string, any>;
dataSource?: Record<string, any>[];
} }
// propsemit // props
// const emit = defineEmits(["modelChange"]);
const props = withDefaults(defineProps<JTableProps>(), { const props = withDefaults(defineProps<JTableProps>(), {
cardBodyClass: '', cardBodyClass: '',
request: undefined, request: undefined,
@ -125,45 +151,56 @@ const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE
const _model = ref<keyof typeof ModelEnum>(props.model ? props.model : ModelEnum.CARD); // const _model = ref<keyof typeof ModelEnum>(props.model ? props.model : ModelEnum.CARD); //
const column = ref<number>(4); const column = ref<number>(4);
const dataSource = ref<Record<string, any>[]>([]) const _dataSource = ref<Record<string, any>[]>([])
const pageIndex = ref<number>(0) const pageIndex = ref<number>(0)
const pageSize = ref<number>(6) const pageSize = ref<number>(6)
const total = ref<number>(0) const total = ref<number>(0)
const _columns = ref<Record<string, any>[]>([]) const _columns = ref<Record<string, any>[]>([])
const loading = ref<boolean>(true)
//
// const slotColumns = computed(() => props.columns.filter((item) => item.scopedSlots))
// //
// //
const modelChange = (type: keyof typeof ModelEnum) => { const modelChange = (type: keyof typeof ModelEnum) => {
_model.value = type _model.value = type
} }
// //
const handleSearch = async (params1?: Record<string, any>) => { const handleSearch = async (_params?: Record<string, any>) => {
loading.value = true
if(props.request) {
const resp = await props.request({ const resp = await props.request({
pageSize: 12, pageSize: 12,
pageIndex: 1, pageIndex: 1,
...params1 ..._params
}) })
if(resp.status === 200){ if(resp.status === 200){
dataSource.value = resp.result?.data || [] //
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 pageIndex.value = resp.result?.pageIndex || 0
pageSize.value = resp.result?.pageSize || 6 pageSize.value = resp.result?.pageSize || 6
total.value = resp.result?.total || 0 total.value = resp.result?.total || 0
} }
} }
} else {
_dataSource.value = props?.dataSource || []
}
loading.value = false
}
const pageChange = (page: number, size: number) => { const pageChange = (page: number, size: number) => {
if(pageSize.value === size) {
handleSearch({ handleSearch({
...props.params,
pageSize: size, pageSize: size,
pageIndex: page, pageIndex: pageSize.value === size ? page : 1,
}) })
} else {
handleSearch({
pageSize: size,
pageIndex: 1,
})
}
} }
watchEffect(() => { watchEffect(() => {

View File

@ -3,7 +3,8 @@ import AIcon from './AIcon'
import PermissionButton from './PermissionButton/index.vue' import PermissionButton from './PermissionButton/index.vue'
import JTable from './Table/index.vue' import JTable from './Table/index.vue'
import TitleComponent from "./TitleComponent/index.vue"; import TitleComponent from "./TitleComponent/index.vue";
import Form from './Form' import Form from './Form';
import CardBox from './CardBox/index.vue';
export default { export default {
install(app: App) { install(app: App) {
@ -12,5 +13,6 @@ export default {
.component('JTable', JTable) .component('JTable', JTable)
.component('TitleComponent', TitleComponent) .component('TitleComponent', TitleComponent)
.component('Form', Form) .component('Form', Form)
.component('CardBox', CardBox)
} }
} }

View File

@ -11,6 +11,7 @@
title: 'ID', title: 'ID',
dataIndex: 'id', dataIndex: 'id',
key: 'id', key: 'id',
scopedSlots: true
}, },
{ {
title: '分类', title: '分类',
@ -20,16 +21,30 @@
]" ]"
:actions="actions" :actions="actions"
:request="request" :request="request"
:rowSelection="rowSelection"
> >
<template #headerTitle> <template #headerTitle>
<a-button type="primary">新增</a-button> <a-button type="primary">新增</a-button>
</template> </template>
<template #cardRender="slotProps"> <template #cardContent="slotProps">
<CardBox :actions="actions"> <h3>{{slotProps.item.name}}</h3>
<template #content> <a-row>
{{slotProps.item.name}} <a-col :span="12">
<div class="card-item-content-text">
设备类型
</div>
<div>直连设备</div>
</a-col>
<a-col :span="12">
<div class="card-item-content-text">
产品名称
</div>
<div>测试固定地址</div>
</a-col>
</a-row>
</template> </template>
</CardBox> <template #id="slotProps">
<a>{{slotProps.row.id}}</a>
</template> </template>
</JTable> </JTable>
</div> </div>
@ -37,21 +52,44 @@
<script setup lang="ts"> <script setup lang="ts">
import server from "@/utils/request"; import server from "@/utils/request";
import CardBox from '@/components/CardBox/index.vue'; import type { ActionsType } from '@/components/Table/index.vue'
import { getImage } from '@/utils/comm';
import type { TableProps, TableColumnType } from 'ant-design-vue';
const request = (data: any) => server.post(`/device-product/_query`, data) const request = (data: any) => server.post(`/device-product/_query`, data)
const actions = [ const actions: ActionsType[] = [
{ {
key: 'edit', key: 'edit',
// disabled: true, // disabled: true,
text: "编辑" text: "编辑",
tooltip: {
title: '编辑'
},
// component: <UnorderedListOutlined />
}, },
{ {
key: 'delete', key: 'delete',
disabled: true, disabled: true,
text: "删除" text: "删除",
tooltip: {
title: '删除'
},
popConfirm: {
title: '确认删除?'
}
} }
] ]
const rowSelection: TableProps['rowSelection'] = {
onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
getCheckboxProps: (record: any) => ({
disabled: record.name === 'Disabled User',
name: record.name,
}),
};
</script> </script>