feat: 表格选择
This commit is contained in:
parent
d2a82edbe4
commit
2d49f87cea
|
@ -7,6 +7,7 @@ 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']
|
ABadge: typeof import('ant-design-vue/es')['Badge']
|
||||||
AButton: typeof import('ant-design-vue/es')['Button']
|
AButton: typeof import('ant-design-vue/es')['Button']
|
||||||
ACard: typeof import('ant-design-vue/es')['Card']
|
ACard: typeof import('ant-design-vue/es')['Card']
|
||||||
|
@ -16,13 +17,12 @@ declare module '@vue/runtime-core' {
|
||||||
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
|
||||||
ADivider: typeof import('ant-design-vue/es')['Divider']
|
ADivider: typeof import('ant-design-vue/es')['Divider']
|
||||||
AEmpty: typeof import('ant-design-vue/es')['Empty']
|
AEmpty: typeof import('ant-design-vue/es')['Empty']
|
||||||
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']
|
||||||
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
|
||||||
|
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||||
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||||
|
|
|
@ -2,17 +2,10 @@
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div
|
<div
|
||||||
class="card-warp"
|
class="card-warp"
|
||||||
:class="{
|
:class="{ active: active ? 'active' : ''}"
|
||||||
hover: maskShow ? 'hover' : '',
|
|
||||||
active: actived ? 'active' : '',
|
|
||||||
}"
|
|
||||||
@click="handleClick"
|
@click="handleClick"
|
||||||
>
|
>
|
||||||
<div
|
<div class="card-content">
|
||||||
class="card-content"
|
|
||||||
@mouseenter="setMaskShow(true)"
|
|
||||||
@mouseleave="setMaskShow(false)"
|
|
||||||
>
|
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :span="6">
|
<a-col :span="6">
|
||||||
<!-- 图片 -->
|
<!-- 图片 -->
|
||||||
|
@ -27,7 +20,7 @@
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<!-- 勾选 -->
|
<!-- 勾选 -->
|
||||||
<div v-if="actived" class="checked-icon">
|
<div v-if="active" class="checked-icon">
|
||||||
<div>
|
<div>
|
||||||
<CheckOutlined />
|
<CheckOutlined />
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,21 +40,12 @@
|
||||||
></BadgeStatus>
|
></BadgeStatus>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 遮罩层 -->
|
|
||||||
<div
|
|
||||||
v-if="showMask"
|
|
||||||
class="card-mask"
|
|
||||||
:class="maskShow ? 'show' : ''"
|
|
||||||
>
|
|
||||||
<slot name="mask"></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 按钮 -->
|
<!-- 按钮 -->
|
||||||
<slot name="bottom-tool">
|
<slot name="bottom-tool">
|
||||||
<div v-if="showTool" class="card-tools">
|
<div v-if="showTool && actions && actions.length" class="card-tools">
|
||||||
<div
|
<div
|
||||||
v-for="item in actions"
|
v-for="item in actions"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
|
@ -70,18 +54,32 @@
|
||||||
delete: item.key === 'delete',
|
delete: item.key === 'delete',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<a-tooltip v-if="item.disabled === true">
|
<a-popconfirm v-if="item.popConfirm" v-bind="item.popConfirm">
|
||||||
<template #title>{{ item.message }}</template>
|
<template v-if="item.key === 'delete'">
|
||||||
<a-button :disabled="item.disabled">
|
<a-button :disabled="item.disabled">
|
||||||
<template #icon><SearchOutlined /></template>
|
<DeleteOutlined />
|
||||||
<span>{{ item.label }}</span>
|
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-tooltip>
|
</template>
|
||||||
|
<template v-else>
|
||||||
<a-button v-else :disabled="item.disabled">
|
<a-button :disabled="item.disabled">
|
||||||
<template #icon><SearchOutlined /></template>
|
<AIcon :type="item.icon" />
|
||||||
<span>{{ item.label }}</span>
|
<span>{{ item.text }}</span>
|
||||||
</a-button>
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</a-popconfirm>
|
||||||
|
<template v-else>
|
||||||
|
<template v-if="item.key === 'delete'">
|
||||||
|
<a-button :disabled="item.disabled">
|
||||||
|
<DeleteOutlined />
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<a-button :disabled="item.disabled">
|
||||||
|
<AIcon :type="item.icon" />
|
||||||
|
<span>{{ item.text }}</span>
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -89,18 +87,26 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { SearchOutlined, CheckOutlined } from '@ant-design/icons-vue';
|
import { SearchOutlined, CheckOutlined, DeleteOutlined } from '@ant-design/icons-vue';
|
||||||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||||
import { StatusColorEnum } from '@/utils/consts.ts';
|
import { StatusColorEnum } from '@/utils/consts.ts';
|
||||||
|
import type { ActionsType } from '@/components/Table/index.vue'
|
||||||
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
type EmitProps = {
|
type EmitProps = {
|
||||||
(e: 'update:modelvalue', data: string | number): void;
|
// (e: 'update:modelValue', data: Record<string, any>): void;
|
||||||
(e: 'actived', data: boolean): void;
|
(e: 'click', data: Record<string, any>): void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TableActionsType = Partial<ActionsType>
|
||||||
|
|
||||||
const emit = defineEmits<EmitProps>();
|
const emit = defineEmits<EmitProps>();
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
value: {
|
||||||
|
type: Object as PropType<Record<string, any>>,
|
||||||
|
default: () => {}
|
||||||
|
},
|
||||||
showStatus: {
|
showStatus: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
@ -109,10 +115,7 @@ const props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
showMask: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
statusText: {
|
statusText: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '正常',
|
default: '正常',
|
||||||
|
@ -125,21 +128,17 @@ const props = defineProps({
|
||||||
type: Object,
|
type: Object,
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
type: Array as any,
|
type: Array as PropType<TableActionsType[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
active: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const maskShow = ref(false);
|
|
||||||
const actived = ref(false);
|
|
||||||
|
|
||||||
const setMaskShow = (val: boolean) => {
|
|
||||||
maskShow.value = val;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
actived.value = !actived.value;
|
emit('click', props.value);
|
||||||
emit('actived', actived.value);
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="jtable-content">
|
<div class="jtable-content">
|
||||||
<!-- <div class="jtable-alert">
|
<div class="jtable-alert" v-if="rowSelection.selectedRowKeys && rowSelection.selectedRowKeys.length">
|
||||||
<a-alert message="Info Text" type="info" />
|
<a-alert :message="'已选择' + rowSelection.selectedRowKeys.length + '项'" type="info" :afterClose="handleAlertClose">
|
||||||
</div> -->
|
<template #closeText>
|
||||||
|
<a>取消选择</a>
|
||||||
|
</template>
|
||||||
|
</a-alert>
|
||||||
|
</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"
|
||||||
|
@ -29,16 +33,7 @@
|
||||||
v-for="(item, index) in _dataSource"
|
v-for="(item, index) in _dataSource"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<CardBox :actions="actions" v-bind="cardProps">
|
<slot name="card" v-bind="item" :index="index"></slot>
|
||||||
<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>
|
||||||
|
@ -46,23 +41,21 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<a-table :rowSelection="rowSelection" :columns="[..._columns]" :dataSource="_dataSource" :pagination="false" :scroll="{ x: 1366 }">
|
<a-table rowKey="id" :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" v-bind="i.tooltip">
|
<a-tooltip v-for="i in actions" :key="i.key" v-bind="i.tooltip">
|
||||||
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
||||||
<a>
|
<a><AIcon :type="i.icon" /></a>
|
||||||
{{i.text}}
|
|
||||||
</a>
|
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
<a v-else @click="i.onClick && i.onClick(record)">
|
<a v-else @click="i.onClick && i.onClick(record)">
|
||||||
{{i.text}}
|
<AIcon :type="i.icon" />
|
||||||
</a>
|
</a>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</a-space>
|
</a-space>
|
||||||
</template>
|
</template> -->
|
||||||
<template v-else-if="column.scopedSlots">
|
<template v-if="column.scopedSlots">
|
||||||
<slot :name="column.key" :row="record"></slot>
|
<slot :name="column.key" :row="record"></slot>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
@ -88,12 +81,11 @@
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
|
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
|
||||||
import type { TableProps } from 'ant-design-vue/es/table'
|
import type { TableProps, ColumnsType } from 'ant-design-vue/es/table'
|
||||||
import type { TooltipProps } from 'ant-design-vue/es/tooltip'
|
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',
|
||||||
|
@ -123,13 +115,17 @@ export interface ActionsType {
|
||||||
icon?: string;
|
icon?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface JTableProps extends TableProps{
|
export interface JColumnsProps extends ColumnsType{
|
||||||
|
scopedSlots?: boolean; // 是否为插槽 true: 是 false: 否
|
||||||
|
}
|
||||||
|
|
||||||
|
export 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>>;
|
||||||
cardBodyClass?: string;
|
cardBodyClass?: string;
|
||||||
columns: Record<string, any>[];
|
columns: JColumnsProps;
|
||||||
params?: Record<string, any> & {
|
params?: Record<string, any> & {
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
pageIndex: number;
|
pageIndex: number;
|
||||||
|
@ -147,6 +143,11 @@ const props = withDefaults(defineProps<JTableProps>(), {
|
||||||
request: undefined,
|
request: undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// emit
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'cancelSelect'): void
|
||||||
|
}>()
|
||||||
|
|
||||||
const simpleImage = Empty.PRESENTED_IMAGE_SIMPLE
|
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); // 模式切换
|
||||||
|
@ -155,16 +156,17 @@ 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>[]>([...props.columns])
|
||||||
const loading = ref<boolean>(true)
|
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 (_params?: Record<string, any>) => {
|
const handleSearch = async (_params?: Record<string, any>) => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
if(props.request) {
|
if(props.request) {
|
||||||
|
@ -194,7 +196,9 @@ const handleSearch = async (_params?: Record<string, any>) => {
|
||||||
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 页码变化
|
||||||
|
*/
|
||||||
const pageChange = (page: number, size: number) => {
|
const pageChange = (page: number, size: number) => {
|
||||||
handleSearch({
|
handleSearch({
|
||||||
...props.params,
|
...props.params,
|
||||||
|
@ -203,22 +207,30 @@ const pageChange = (page: number, size: number) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// alert关闭,取消选择
|
||||||
|
const handleAlertClose = () => {
|
||||||
|
emit('cancelSelect')
|
||||||
|
}
|
||||||
|
|
||||||
|
// watchEffect(() => {
|
||||||
|
// if(Array.isArray(props.actions) && props.actions.length) {
|
||||||
|
// _columns.value = [...props.columns,
|
||||||
|
// {
|
||||||
|
// title: '操作',
|
||||||
|
// key: 'action',
|
||||||
|
// fixed: 'right',
|
||||||
|
// width: 250
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// } else {
|
||||||
|
// _columns.value = [...props.columns]
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if(Array.isArray(props.actions) && props.actions.length) {
|
|
||||||
_columns.value = [...props.columns,
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
key: 'action',
|
|
||||||
fixed: 'right',
|
|
||||||
width: 250
|
|
||||||
}
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
_columns.value = [...props.columns]
|
|
||||||
}
|
|
||||||
handleSearch(props.params)
|
handleSearch(props.params)
|
||||||
})
|
})
|
||||||
|
// TODO 选择的双向绑定和图标的渲染
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
@ -250,11 +262,13 @@ watchEffect(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.jtable-content {
|
.jtable-content {
|
||||||
|
.jtable-alert {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
.jtable-card {
|
.jtable-card {
|
||||||
.jtable-card-items {
|
.jtable-card-items {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-gap: 26px;
|
grid-gap: 26px;
|
||||||
// grid-template-columns: repeat(4, 1fr);
|
|
||||||
.jtable-card-item {
|
.jtable-card-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
.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-card {
|
|
||||||
.jtable-card-items {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: 26px;
|
|
||||||
// grid-template-columns: repeat(4, 1fr);
|
|
||||||
.jtable-card-item {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.jtable-pagination {
|
|
||||||
position: absolute;
|
|
||||||
right: 24px;
|
|
||||||
bottom: 24px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,168 +0,0 @@
|
||||||
import { UnorderedListOutlined, AppstoreOutlined } from '@ant-design/icons-vue'
|
|
||||||
import styles from './index.module.less'
|
|
||||||
import { Pagination, Table, Empty } from 'ant-design-vue'
|
|
||||||
import type { TableProps } from 'ant-design-vue/es/table'
|
|
||||||
|
|
||||||
enum ModelEnum {
|
|
||||||
TABLE = 'TABLE',
|
|
||||||
CARD = 'CARD',
|
|
||||||
}
|
|
||||||
|
|
||||||
export declare type RequestData = {
|
|
||||||
code: string;
|
|
||||||
result: {
|
|
||||||
data: any[] | undefined;
|
|
||||||
pageIndex: number;
|
|
||||||
pageSize: number;
|
|
||||||
total: number;
|
|
||||||
};
|
|
||||||
status: number;
|
|
||||||
} & Record<string, any>;
|
|
||||||
|
|
||||||
interface JTableProps extends TableProps{
|
|
||||||
request: (params: Record<string, any> & {
|
|
||||||
pageSize: number;
|
|
||||||
pageIndex: number;
|
|
||||||
}) => Promise<Partial<RequestData>>;
|
|
||||||
cardBodyClass: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const JTable = defineComponent<JTableProps>({
|
|
||||||
name: 'JTable',
|
|
||||||
slots: [
|
|
||||||
'headerTitle', // 顶部左边插槽
|
|
||||||
'cardRender', // 卡片内容
|
|
||||||
],
|
|
||||||
emits: [
|
|
||||||
'modelChange', // 切换卡片和表格
|
|
||||||
],
|
|
||||||
props: {
|
|
||||||
cardBodyClass: '',
|
|
||||||
request: undefined,
|
|
||||||
columns: []
|
|
||||||
} as any,
|
|
||||||
setup(props ,{ slots, emit }){
|
|
||||||
const model = ref<keyof typeof ModelEnum>(ModelEnum.CARD); // 模式切换
|
|
||||||
const column = ref<number>(3);
|
|
||||||
console.log(props.columns, props.request)
|
|
||||||
const dataSource = ref<any[]>([
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
name: '胡彦斌',
|
|
||||||
age: 32,
|
|
||||||
address: '西湖区湖底公园1号',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
name: '胡彦祖1',
|
|
||||||
age: 42,
|
|
||||||
address: '西湖区湖底公园1号',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '3',
|
|
||||||
name: '胡彦斌',
|
|
||||||
age: 32,
|
|
||||||
address: '西湖区湖底公园1号',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '4',
|
|
||||||
name: '胡彦祖1',
|
|
||||||
age: 42,
|
|
||||||
address: '西湖区湖底公园1号',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '5',
|
|
||||||
name: '胡彦斌',
|
|
||||||
age: 32,
|
|
||||||
address: '西湖区湖底公园1号',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '6',
|
|
||||||
name: '胡彦祖1',
|
|
||||||
age: 42,
|
|
||||||
address: '西湖区湖底公园1号',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 请求数据
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
return () => <div class={styles["jtable-body"]}>
|
|
||||||
<div class={styles["jtable-body-header"]}>
|
|
||||||
<div class={styles["jtable-body-header-left"]}>
|
|
||||||
{/* 顶部左边插槽 */}
|
|
||||||
{slots.headerTitle && slots.headerTitle()}
|
|
||||||
</div>
|
|
||||||
<div class={styles["jtable-body-header-right"]}>
|
|
||||||
{/* <Space> */}
|
|
||||||
<div class={[styles["jtable-setting-item"], ModelEnum.CARD === model.value ? styles['active'] : '']} onClick={() => {
|
|
||||||
model.value = ModelEnum.CARD
|
|
||||||
}}>
|
|
||||||
<AppstoreOutlined />
|
|
||||||
</div>
|
|
||||||
<div class={[styles["jtable-setting-item"], ModelEnum.TABLE === model.value ? styles['active'] : '']} onClick={() => {
|
|
||||||
model.value = ModelEnum.TABLE
|
|
||||||
}}>
|
|
||||||
<UnorderedListOutlined />
|
|
||||||
</div>
|
|
||||||
{/* </Space> */}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* content */}
|
|
||||||
<div class={styles['jtable-content']}>
|
|
||||||
{
|
|
||||||
model.value === ModelEnum.CARD ?
|
|
||||||
<div class={styles['jtable-card']}>
|
|
||||||
{
|
|
||||||
dataSource.value.length ?
|
|
||||||
<div
|
|
||||||
class={styles['jtable-card-items']}
|
|
||||||
style={{gridTemplateColumns: `repeat(${column.value}, 1fr)`}}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
dataSource.value.map(item => slots.cardRender ?
|
|
||||||
<div class={[styles['jtable-card-item'], props.cardBodyClass]}>{slots.cardRender(item)}</div>
|
|
||||||
: null)
|
|
||||||
}
|
|
||||||
</div> :
|
|
||||||
<div><Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /></div>
|
|
||||||
}
|
|
||||||
</div> :
|
|
||||||
<div>
|
|
||||||
<Table
|
|
||||||
dataSource={dataSource.value}
|
|
||||||
columns={props.columns}
|
|
||||||
pagination={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
{/* 分页 */}
|
|
||||||
{
|
|
||||||
dataSource.value.length &&
|
|
||||||
<div class={styles['jtable-pagination']}>
|
|
||||||
<Pagination
|
|
||||||
size="small"
|
|
||||||
total={50}
|
|
||||||
showTotal={(total) => {
|
|
||||||
const min = 1
|
|
||||||
const max = 1
|
|
||||||
return `第 ${min} - ${max} 条/总共 ${total} 条`
|
|
||||||
}}
|
|
||||||
onChange={() => {
|
|
||||||
|
|
||||||
}}
|
|
||||||
onShowSizeChange={() => {
|
|
||||||
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default JTable
|
|
|
@ -11,8 +11,8 @@
|
||||||
status="disable"
|
status="disable"
|
||||||
:statusNames="{ disable: StatusColorEnum.error }"
|
:statusNames="{ disable: StatusColorEnum.error }"
|
||||||
statusText="正常"
|
statusText="正常"
|
||||||
:showMask="false"
|
|
||||||
:actions="actions"
|
:actions="actions"
|
||||||
|
v-model="data"
|
||||||
>
|
>
|
||||||
<template #img>
|
<template #img>
|
||||||
<img :src="getImage('/device-product.png')" />
|
<img :src="getImage('/device-product.png')" />
|
||||||
|
@ -63,6 +63,10 @@ const actions = ref([
|
||||||
label: '删除',
|
label: '删除',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
const data = ref({
|
||||||
|
id: 123
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -18,34 +18,66 @@
|
||||||
dataIndex: 'classifiedName',
|
dataIndex: 'classifiedName',
|
||||||
key: 'classifiedName',
|
key: 'classifiedName',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'action',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 250,
|
||||||
|
scopedSlots: true
|
||||||
|
}
|
||||||
]"
|
]"
|
||||||
:actions="actions"
|
:actions="actions"
|
||||||
:request="request"
|
:request="request"
|
||||||
:rowSelection="rowSelection"
|
:rowSelection="{
|
||||||
|
selectedRowKeys: _selectedRowKeys,
|
||||||
|
onChange: onSelectChange
|
||||||
|
}"
|
||||||
|
@cancelSelect="cancelSelect"
|
||||||
>
|
>
|
||||||
<template #headerTitle>
|
<template #headerTitle>
|
||||||
<a-button type="primary">新增</a-button>
|
<a-button type="primary">新增</a-button>
|
||||||
</template>
|
</template>
|
||||||
<template #cardContent="slotProps">
|
<template #card="slotProps">
|
||||||
<h3>{{slotProps.item.name}}</h3>
|
<CardBox :value="slotProps" @click="handleClick" :actions="actions" v-bind="slotProps" :active="_selectedRowKeys.includes(slotProps.id)">
|
||||||
<a-row>
|
<template #img>
|
||||||
<a-col :span="12">
|
<slot name="img">
|
||||||
<div class="card-item-content-text">
|
<img :src="getImage('/device-product.png')" />
|
||||||
设备类型
|
</slot>
|
||||||
</div>
|
</template>
|
||||||
<div>直连设备</div>
|
<template #content>
|
||||||
</a-col>
|
<h3>{{slotProps.name}}</h3>
|
||||||
<a-col :span="12">
|
<a-row>
|
||||||
<div class="card-item-content-text">
|
<a-col :span="12">
|
||||||
产品名称
|
<div class="card-item-content-text">
|
||||||
</div>
|
设备类型
|
||||||
<div>测试固定地址</div>
|
</div>
|
||||||
</a-col>
|
<div>直连设备</div>
|
||||||
</a-row>
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div class="card-item-content-text">
|
||||||
|
产品名称
|
||||||
|
</div>
|
||||||
|
<div>测试固定地址</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
</template>
|
</template>
|
||||||
<template #id="slotProps">
|
<template #id="slotProps">
|
||||||
<a>{{slotProps.row.id}}</a>
|
<a>{{slotProps.row.id}}</a>
|
||||||
</template>
|
</template>
|
||||||
|
<template #action="slotProps">
|
||||||
|
<a-space :size="16">
|
||||||
|
<a-tooltip v-for="i in actions" :key="i.key" v-bind="i.tooltip">
|
||||||
|
<a-popconfirm v-if="i.popConfirm" v-bind="i.popConfirm">
|
||||||
|
<a-button style="padding: 0" type="link"><AIcon :type="i.icon" /></a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
<a-button style="padding: 0" type="link" v-else @click="i.onClick && i.onClick(slotProps)">
|
||||||
|
<AIcon :type="i.icon" />
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
</JTable>
|
</JTable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,7 +86,6 @@
|
||||||
import server from "@/utils/request";
|
import server from "@/utils/request";
|
||||||
import type { ActionsType } from '@/components/Table/index.vue'
|
import type { ActionsType } from '@/components/Table/index.vue'
|
||||||
import { getImage } from '@/utils/comm';
|
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: ActionsType[] = [
|
const actions: ActionsType[] = [
|
||||||
|
@ -65,30 +96,50 @@ const actions: ActionsType[] = [
|
||||||
tooltip: {
|
tooltip: {
|
||||||
title: '编辑'
|
title: '编辑'
|
||||||
},
|
},
|
||||||
// component: <UnorderedListOutlined />
|
icon: 'icon-rizhifuwu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'import',
|
||||||
|
// disabled: true,
|
||||||
|
text: "导入",
|
||||||
|
tooltip: {
|
||||||
|
title: '导入'
|
||||||
|
},
|
||||||
|
icon: 'icon-xiazai'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'delete',
|
key: 'delete',
|
||||||
disabled: true,
|
// disabled: true,
|
||||||
text: "删除",
|
text: "删除",
|
||||||
tooltip: {
|
tooltip: {
|
||||||
title: '删除'
|
title: '删除'
|
||||||
},
|
},
|
||||||
popConfirm: {
|
popConfirm: {
|
||||||
title: '确认删除?'
|
title: '确认删除?'
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
const rowSelection: TableProps['rowSelection'] = {
|
const _selectedRowKeys = ref<string[]>([])
|
||||||
onChange: (selectedRowKeys: string[], selectedRows: any[]) => {
|
|
||||||
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
const onSelectChange = (keys: string[]) => {
|
||||||
},
|
_selectedRowKeys.value = [...keys]
|
||||||
getCheckboxProps: (record: any) => ({
|
}
|
||||||
disabled: record.name === 'Disabled User',
|
|
||||||
name: record.name,
|
const cancelSelect = () => {
|
||||||
}),
|
_selectedRowKeys.value = []
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const handleClick = (dt: any) => {
|
||||||
|
// _selectedRowKeys.value = [dt.id] // 单选
|
||||||
|
// _selectedRowKeys.value = [..._selectedRowKeys.value, dt.id] // 多选
|
||||||
|
if(_selectedRowKeys.value.includes(dt.id)) {
|
||||||
|
const _index = _selectedRowKeys.value.findIndex(i => i === dt.id)
|
||||||
|
_selectedRowKeys.value.splice(_index, 1)
|
||||||
|
} else {
|
||||||
|
_selectedRowKeys.value = [..._selectedRowKeys.value, dt.id]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue