feat: 表格插槽
This commit is contained in:
parent
aab98f3ddf
commit
e3c3e43b31
|
@ -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']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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; // 显示table还是card
|
model?: keyof typeof ModelEnum | undefined; // 显示table还是card
|
||||||
actions?: ActionsType[]
|
actions?: ActionsType[];
|
||||||
|
noPagination?: boolean;
|
||||||
|
rowSelection?: TableProps['rowSelection'];
|
||||||
|
cardProps?: Record<string, any>;
|
||||||
|
dataSource?: Record<string, any>[];
|
||||||
}
|
}
|
||||||
// props和emit
|
// 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(() => {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue