分离卡片列表组件.
This commit is contained in:
368
orion-ops-ui/src/components/card-list/index.vue
Normal file
368
orion-ops-ui/src/components/card-list/index.vue
Normal file
@@ -0,0 +1,368 @@
|
||||
<template>
|
||||
<div class="card-list-layout">
|
||||
<!-- 头部部分-固定 -->
|
||||
<div class="card-list-layout-header" :style="{width: headerWidth}">
|
||||
<div class="card-list-layout-header-wrapper">
|
||||
<!-- 信息部分 -->
|
||||
<div class="card-list-info">
|
||||
<!-- 路由面包屑 -->
|
||||
<Breadcrumb />
|
||||
<!-- 分页部分 -->
|
||||
<div class="pagination-wrapper">
|
||||
<a-pagination v-if="pagination"
|
||||
size="mini"
|
||||
v-model:current="pagination.current"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
v-bind="pagination" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作部分 -->
|
||||
<div class="card-list-handler">
|
||||
<!-- 左侧固定 -->
|
||||
<div class="card-list-handler-left">
|
||||
<a-space>
|
||||
<!-- 创建 -->
|
||||
<div v-if="!handleVisible.disableAdd"
|
||||
class="header-icon-wrapper"
|
||||
title="创建"
|
||||
@click="emits('add')">
|
||||
<icon-plus />
|
||||
</div>
|
||||
</a-space>
|
||||
<!-- 左侧侧操作槽位 -->
|
||||
<slot name="leftHandle" />
|
||||
</div>
|
||||
<!-- 右侧固定 -->
|
||||
<div class="card-list-handler-right">
|
||||
<!-- 右侧操作槽位 -->
|
||||
<slot name="rightHandle" />
|
||||
<a-space>
|
||||
<!-- 搜索框 -->
|
||||
<div v-if="!handleVisible.disableSearchInput"
|
||||
class="header-input-wrapper"
|
||||
:style="{width: searchInputWidth}">
|
||||
<a-input :default-value="searchValue"
|
||||
size="small"
|
||||
placeholder="输入名称/地址"
|
||||
allow-clear
|
||||
@input="e => emits('update:searchValue', e)"
|
||||
@change="e => emits('update:searchValue', e)"
|
||||
@keydown.enter="emits('search')" />
|
||||
</div>
|
||||
<!-- 过滤 -->
|
||||
<div v-if="!handleVisible.disableFilter"
|
||||
class="header-icon-wrapper"
|
||||
title="选择过滤条件">
|
||||
<icon-filter />
|
||||
</div>
|
||||
<!-- 搜索 -->
|
||||
<div v-if="!handleVisible.disableSearch"
|
||||
class="header-icon-wrapper"
|
||||
title="搜索"
|
||||
@click="emits('search')">
|
||||
<icon-search />
|
||||
</div>
|
||||
<!-- 重置 -->
|
||||
<div v-if="!handleVisible.disableReset"
|
||||
class="header-icon-wrapper"
|
||||
title="重置"
|
||||
@click="emits('reset')">
|
||||
<icon-refresh />
|
||||
</div>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 身体部分 -->
|
||||
<div class="card-list-layout-body">
|
||||
<!-- 卡片列表 -->
|
||||
<a-row v-if="list.length !== 0"
|
||||
:gutter="cardLayoutGutter">
|
||||
<!-- 添加卡片 -->
|
||||
<a-col v-if="createCardPosition === 'head'" v-bind="cardLayoutCols">
|
||||
<create-card :card-height="cardHeight"
|
||||
:create-card-description="createCardDescription"
|
||||
@click="emits('add')" />
|
||||
</a-col>
|
||||
<!-- 数据卡片 -->
|
||||
<a-col v-for="(item, index) in list"
|
||||
:key="item[key]"
|
||||
v-bind="cardLayoutCols"
|
||||
:class="{
|
||||
'disabled-col': item.disabled === true
|
||||
}">
|
||||
<a-card :class="{
|
||||
'general-card': true,
|
||||
'card-list-item': true,
|
||||
'card-list-item-disabled': item.disabled === true
|
||||
}"
|
||||
:style="{ height: `${cardHeight}px` }"
|
||||
:body-style="{ height: 'calc(100% - 58px)' }"
|
||||
:bordered="false"
|
||||
:hoverable="true">
|
||||
<!-- 标题 -->
|
||||
<template #title>
|
||||
<slot name="title" :record="item" :index="index" :key="item[key]" />
|
||||
</template>
|
||||
<!-- 拓展部分 -->
|
||||
<template #extra>
|
||||
<slot name="extra" :record="item" :index="index" :key="item[key]" />
|
||||
</template>
|
||||
<!-- 内容 -->
|
||||
<slot name="card" :record="item" :index="index" :key="item[key]" />
|
||||
</a-card>
|
||||
</a-col>
|
||||
<!-- 添加卡片 -->
|
||||
<a-col v-if="createCardPosition === 'tail'" v-bind="cardLayoutCols">
|
||||
<create-card :card-height="cardHeight"
|
||||
:create-card-description="createCardDescription"
|
||||
@click="emits('add')" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- 空列表 -->
|
||||
<template v-else>
|
||||
<a-card class="general-card empty-list-card"
|
||||
:style="{ height: `${cardHeight * 2 + 16}px` }"
|
||||
:body-style="{ height: '100%' }">
|
||||
<a-empty :class="{
|
||||
'empty-list-card-body': true,
|
||||
'empty-list-card-body-creatable': emptyToCreate
|
||||
}"
|
||||
:description="emptyDescription"
|
||||
@click="emits('add')" />
|
||||
</a-card>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'card-list'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { compile, computed, h, PropType } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { PaginationProps, ResponsiveValue } from '@arco-design/web-vue';
|
||||
import { Position, CardRecord, ColResponsiveValue, HandleVisible } from './types';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const headerWidth = computed(() => {
|
||||
const menuWidth = appStore.menu && !appStore.topMenu && !appStore.hideMenu
|
||||
? appStore.menuCollapse ? 48 : appStore.menuWidth
|
||||
: 0;
|
||||
return `calc(100% - ${menuWidth}px)`;
|
||||
});
|
||||
|
||||
const emits = defineEmits(['add', 'update:searchValue', 'search', 'reset']);
|
||||
|
||||
defineProps({
|
||||
key: {
|
||||
type: String,
|
||||
default: () => 'id'
|
||||
},
|
||||
pagination: {
|
||||
type: Object as PropType<PaginationProps> | PropType<boolean>,
|
||||
default: () => false
|
||||
},
|
||||
cardHeight: Number,
|
||||
searchInputWidth: {
|
||||
type: String,
|
||||
default: () => '200px'
|
||||
},
|
||||
searchValue: {
|
||||
type: String,
|
||||
default: () => ''
|
||||
},
|
||||
createCardDescription: {
|
||||
type: String,
|
||||
default: () => '点击此处进行创建'
|
||||
},
|
||||
createCardPosition: {
|
||||
type: String as PropType<Position>,
|
||||
default: () => '暂无数据 点击此处进行创建'
|
||||
},
|
||||
emptyToCreate: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
},
|
||||
emptyDescription: {
|
||||
type: String,
|
||||
default: () => '暂无数据 点击此处进行创建'
|
||||
},
|
||||
cardLayoutGutter: {
|
||||
type: [Number, Array] as PropType<Number> |
|
||||
PropType<ResponsiveValue> |
|
||||
PropType<Array<Number>> |
|
||||
PropType<Array<ResponsiveValue>>,
|
||||
default: () => [16, 16]
|
||||
},
|
||||
cardLayoutCols: {
|
||||
type: Object as PropType<ColResponsiveValue>,
|
||||
default: () => {
|
||||
return {
|
||||
span: 6
|
||||
};
|
||||
}
|
||||
},
|
||||
handleVisible: {
|
||||
type: Object as PropType<HandleVisible>,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
list: {
|
||||
type: Array as PropType<Array<CardRecord>>,
|
||||
default: () => []
|
||||
},
|
||||
});
|
||||
|
||||
// 创建卡片
|
||||
const CreateCard = {
|
||||
props: ['cardHeight', 'createCardDescription'],
|
||||
setup(props: { cardHeight: any; createCardDescription: any; }) {
|
||||
return () => {
|
||||
return h(compile(`
|
||||
<a-card class="general-card card-list-item create-card"
|
||||
:style="{ height: '${props.cardHeight}px' }"
|
||||
:body-style="{ height: '100%' }"
|
||||
:bordered="false"
|
||||
:hoverable="true">
|
||||
<div class="create-card-body">
|
||||
<icon-plus class="create-card-body-icon" />
|
||||
<span class="create-card-body-text">${props.createCardDescription}</span>
|
||||
</div>
|
||||
</a-card>
|
||||
`));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@header-info-height: 48px;
|
||||
@header-handler-height: 48px;
|
||||
@top-height: 16 + @header-info-height + @header-handler-height + 12px;
|
||||
|
||||
.card-list-layout {
|
||||
|
||||
&-header {
|
||||
margin: -16px -16px 0 -16px;
|
||||
padding: 16px 16px 12px 16px;
|
||||
position: fixed;
|
||||
background: var(--color-fill-2);
|
||||
z-index: 999;
|
||||
height: @top-height;
|
||||
transition: none;
|
||||
|
||||
&-wrapper {
|
||||
background: var(--color-bg-4);
|
||||
padding: 0 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&-body {
|
||||
margin-top: @top-height - 16px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.disabled-col {
|
||||
cursor: not-allowed;
|
||||
|
||||
.card-list-item-disabled {
|
||||
pointer-events: none;
|
||||
opacity: .5;
|
||||
background: var(--color-bg-1);
|
||||
}
|
||||
}
|
||||
|
||||
.card-list-info {
|
||||
height: @header-info-height;
|
||||
border-bottom: 1px solid var(--color-border-2);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-list-handler {
|
||||
height: @header-handler-height;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.header-icon-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 27px;
|
||||
padding: 6px;
|
||||
color: var(--color-text-2);
|
||||
background: var(--color-fill-2);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
transition: background-color 0.1s cubic-bezier(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
.header-icon-wrapper:hover {
|
||||
background: var(--color-fill-3);
|
||||
}
|
||||
|
||||
:deep(.create-card) {
|
||||
|
||||
&-body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
&-icon {
|
||||
font-size: 18px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.empty-list-card {
|
||||
|
||||
&-body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&-body-creatable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
35
orion-ops-ui/src/components/card-list/types.ts
Normal file
35
orion-ops-ui/src/components/card-list/types.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { ResponsiveValue } from '@arco-design/web-vue';
|
||||
|
||||
/**
|
||||
* 创建卡片位置
|
||||
*/
|
||||
export type Position = 'head' | 'tail' | false
|
||||
|
||||
/**
|
||||
* 卡片字段
|
||||
*/
|
||||
export interface CardRecord {
|
||||
disabled?: boolean;
|
||||
|
||||
[name: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* col 响应式值
|
||||
*/
|
||||
export interface ColResponsiveValue extends ResponsiveValue {
|
||||
span?: number;
|
||||
offset?: number;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示的操作
|
||||
*/
|
||||
export interface HandleVisible {
|
||||
disableAdd?: boolean;
|
||||
disableSearchInput?: boolean;
|
||||
disableFilter?: boolean;
|
||||
disableSearch?: boolean;
|
||||
disableReset?: boolean;
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from 'echarts/components';
|
||||
import Chart from './chart/index.vue';
|
||||
import Breadcrumb from './breadcrumb/index.vue';
|
||||
import CardList from './card-list/index.vue';
|
||||
|
||||
use([
|
||||
CanvasRenderer,
|
||||
@@ -31,5 +32,6 @@ export default {
|
||||
Vue.component('Chart', Chart);
|
||||
Vue.component('Breadcrumb', Breadcrumb);
|
||||
Vue.component('a-query-header', AQueryHeader);
|
||||
Vue.component('card-list', CardList);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script lang="tsx">
|
||||
import { defineComponent, ref, h, compile, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter, RouteRecordRaw } from 'vue-router';
|
||||
import { compile, computed, defineComponent, h, ref } from 'vue';
|
||||
import type { RouteMeta } from 'vue-router';
|
||||
import { RouteRecordRaw, useRoute, useRouter } from 'vue-router';
|
||||
import { useAppStore } from '@/store';
|
||||
import { listenerRouteChange } from '@/utils/route-listener';
|
||||
import { openWindow, regexUrl } from '@/utils';
|
||||
@@ -11,7 +10,6 @@
|
||||
export default defineComponent({
|
||||
emit: ['collapse'],
|
||||
setup() {
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStore();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { PaginationProps, TableRowSelection } from '@arco-design/web-vue';
|
||||
import { ColResponsiveValue } from '@/components/card-list/types';
|
||||
import { reactive } from 'vue';
|
||||
|
||||
/**
|
||||
* FIXME DELETE
|
||||
* 默认分页
|
||||
*/
|
||||
export const defaultPagination = (): PaginationProps => {
|
||||
@@ -15,6 +17,7 @@ export const defaultPagination = (): PaginationProps => {
|
||||
};
|
||||
|
||||
/**
|
||||
* FIXME DELETE
|
||||
* 默认行选择器
|
||||
*/
|
||||
export const defaultRowSelection = (): TableRowSelection => {
|
||||
@@ -25,6 +28,20 @@ export const defaultRowSelection = (): TableRowSelection => {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 卡片列表列布局
|
||||
*/
|
||||
export const useCardColLayout = (): ColResponsiveValue => {
|
||||
return {
|
||||
xs: 24,
|
||||
sm: 12,
|
||||
md: 8,
|
||||
lg: 8,
|
||||
xl: 6,
|
||||
xxl: 4,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建列表分页
|
||||
*/
|
||||
@@ -58,9 +75,9 @@ export const useCardPagination = (): PaginationProps => {
|
||||
* 创建行选择器
|
||||
*/
|
||||
export const useRowSelection = (type = 'checkbox'): TableRowSelection => {
|
||||
return {
|
||||
return reactive({
|
||||
type: type as any,
|
||||
showCheckedAll: true,
|
||||
onlyCurrent: true,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,111 +1,28 @@
|
||||
<template>
|
||||
<div class="card-list-layout">
|
||||
<!-- 头部部分-固定 -->
|
||||
<div class="card-list-layout-header" :style="{width: headerWidth}">
|
||||
<div class="card-list-layout-header-wrapper">
|
||||
<!-- 信息部分 -->
|
||||
<div class="card-list-info">
|
||||
<!-- 路由面包屑 -->
|
||||
<Breadcrumb />
|
||||
<!-- 分页部分 -->
|
||||
<div class="pagination-wrapper">
|
||||
<a-pagination v-if="pagination"
|
||||
size="mini"
|
||||
v-model:current="pagination.current"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
v-bind="pagination" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作部分 -->
|
||||
<div class="card-list-handler">
|
||||
<!-- 左侧固定 -->
|
||||
<div class="card-list-handler-left">
|
||||
<a-space>
|
||||
<!-- 创建 -->
|
||||
<div class="header-icon-wrapper" title="创建">
|
||||
<icon-plus />
|
||||
</div>
|
||||
<!-- 条件显示 -->
|
||||
|
||||
</a-space>
|
||||
</div>
|
||||
<!-- 右侧固定 -->
|
||||
<div class="card-list-handler-right">
|
||||
<a-space>
|
||||
<!-- 搜索框 -->
|
||||
<a-input size="small"
|
||||
placeholder="输入名称/地址"
|
||||
allow-clear />
|
||||
<!-- 过滤 -->
|
||||
<div class="header-icon-wrapper" title="选择过滤条件">
|
||||
<icon-filter />
|
||||
</div>
|
||||
<!-- 搜索 -->
|
||||
<div class="header-icon-wrapper" title="搜索">
|
||||
<icon-search />
|
||||
</div>
|
||||
<!-- 重置 -->
|
||||
<div class="header-icon-wrapper" title="重置">
|
||||
<icon-refresh />
|
||||
</div>
|
||||
</a-space>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 身体部分 -->
|
||||
<div class="card-list-layout-body">
|
||||
<!-- 卡片列表 -->
|
||||
<a-row v-if="list.length !== 0"
|
||||
:gutter="cardLayoutGutter">
|
||||
<!-- 添加卡片 -->
|
||||
<a-col v-if="createCardPosition === 'head'" v-bind="cardLayoutCols">
|
||||
<create-card :card-height="cardHeight" :create-card-description="createCardDescription" />
|
||||
</a-col>
|
||||
<!-- 数据卡片 -->
|
||||
<a-col v-for="(item, index) in list"
|
||||
:key="item[key]"
|
||||
v-bind="cardLayoutCols"
|
||||
:class="{
|
||||
'disabled-col': item.disabled === true
|
||||
}">
|
||||
<a-card :class="{
|
||||
'general-card': true,
|
||||
'card-list-item': true,
|
||||
'card-list-item-disabled': item.disabled === true
|
||||
}"
|
||||
:style="{ height: `${cardHeight}px` }"
|
||||
:body-style="{ height: 'calc(100% - 58px)' }"
|
||||
:bordered="false"
|
||||
:hoverable="true">
|
||||
<!-- 标题 -->
|
||||
<template #title>
|
||||
<slot name="title" :record="item" :index="index" :key="item[key]" />
|
||||
</template>
|
||||
<!-- 拓展部分 -->
|
||||
<template #extra>
|
||||
<slot name="extra" :record="item" :index="index" :key="item[key]" />
|
||||
</template>
|
||||
<!-- 内容 -->
|
||||
<slot name="card" :record="item" :index="index" :key="item[key]" />
|
||||
</a-card>
|
||||
</a-col>
|
||||
<!-- 添加卡片 -->
|
||||
<a-col v-if="createCardPosition === 'tail'" v-bind="cardLayoutCols">
|
||||
<create-card :card-height="cardHeight" :create-card-description="createCardDescription" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- 空列表 -->
|
||||
<template v-else>
|
||||
<a-card class="general-card empty-list-card"
|
||||
:style="{ height: `${cardHeight * 2 + 16}px` }"
|
||||
:body-style="{ height: '100%' }">
|
||||
<a-empty :class="{'empty-list-card-body': true, 'empty-list-card-body-creatable': emptyToCreate }"
|
||||
:description="emptyDescription" />
|
||||
</a-card>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<card-list ref="cardList"
|
||||
v-model:searchValue="formModel.name"
|
||||
create-card-position="head"
|
||||
:card-height="180"
|
||||
:list="list"
|
||||
:pagination="pagination"
|
||||
:card-layout-cols="cardColLayout"
|
||||
@add="add"
|
||||
@search="search"
|
||||
@reset="reset">
|
||||
<!-- 标题 -->
|
||||
<template #title="{ record }">
|
||||
{{ record.name }}
|
||||
</template>
|
||||
<!-- 标题拓展 -->
|
||||
<template #extra="{ index }">
|
||||
{{ index }}
|
||||
</template>
|
||||
<!-- 卡片 -->
|
||||
<template #card="{ record }">
|
||||
{{ record }}
|
||||
</template>
|
||||
</card-list>
|
||||
{{ formModel }}
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -115,248 +32,38 @@
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { compile, computed, h, PropType } from 'vue';
|
||||
import { useAppStore } from '@/store';
|
||||
import { PaginationProps, ResponsiveValue } from '@arco-design/web-vue';
|
||||
import { useCardPagination, useCardColLayout } from '@/types/table';
|
||||
import { reactive, ref } from 'vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
const headerWidth = computed(() => {
|
||||
const menuWidth = appStore.menu && !appStore.topMenu && !appStore.hideMenu
|
||||
? appStore.menuCollapse ? 48 : appStore.menuWidth
|
||||
: 0;
|
||||
return `calc(100% - ${menuWidth}px)`;
|
||||
const formModel = reactive({
|
||||
name: undefined
|
||||
});
|
||||
|
||||
export type Position = 'head' | 'tail' | false
|
||||
const cardColLayout = useCardColLayout();
|
||||
const pagination = useCardPagination();
|
||||
const list = ref<Array<any>>([]);
|
||||
|
||||
export interface CardList {
|
||||
disabled?: boolean;
|
||||
|
||||
[name: string]: any;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
list.value.push({
|
||||
id: i + 1,
|
||||
name: `名称 ${i + 1}`,
|
||||
host: `192.168.1.${i}`,
|
||||
disabled: i === 0
|
||||
});
|
||||
}
|
||||
|
||||
defineProps({
|
||||
key: {
|
||||
type: String,
|
||||
default: () => 'id'
|
||||
},
|
||||
pagination: {
|
||||
type: Object as PropType<PaginationProps> | PropType<boolean>,
|
||||
default: () => false
|
||||
},
|
||||
cardHeight: Number,
|
||||
createCardDescription: {
|
||||
type: String,
|
||||
default: () => '点击此处进行创建'
|
||||
},
|
||||
emptyToCreate: {
|
||||
type: Boolean,
|
||||
default: () => true
|
||||
},
|
||||
emptyDescription: {
|
||||
type: String,
|
||||
default: () => '暂无数据 点击此处进行创建'
|
||||
},
|
||||
createCardPosition: {
|
||||
type: String as PropType<Position>,
|
||||
default: () => '暂无数据 点击此处进行创建'
|
||||
},
|
||||
cardLayoutGutter: {
|
||||
type: [Number, Array] as PropType<Number> |
|
||||
PropType<ResponsiveValue> |
|
||||
PropType<Array<Number>> |
|
||||
PropType<Array<ResponsiveValue>>,
|
||||
default: () => [16, 16]
|
||||
},
|
||||
cardLayoutCols: {
|
||||
type: Object as PropType<ResponsiveValue & { span?: number, offset?: number, order?: number }>,
|
||||
default: () => {
|
||||
return {
|
||||
span: 6
|
||||
};
|
||||
}
|
||||
},
|
||||
list: {
|
||||
type: Array as PropType<Array<CardList>>,
|
||||
default: () => []
|
||||
},
|
||||
});
|
||||
|
||||
// props
|
||||
// const pagination = useCardPagination();
|
||||
// const cardHeight = 120;
|
||||
// const createCardDescription = '点击此处进行创建';
|
||||
// const emptyToCreate = true;
|
||||
// const emptyDescription = '暂无数据 点击此处进行创建';
|
||||
// // head tail false
|
||||
// const createCardPosition = 'head';
|
||||
// const cardLayoutGutter = [
|
||||
// { xs: 16, sm: 16, md: 16, lg: 16, xl: 16, xxl: 16 },
|
||||
// { xs: 16, sm: 16, md: 16, lg: 16, xl: 16, xxl: 16 }
|
||||
// ];
|
||||
// const cardLayoutCols = {
|
||||
// xs: 24,
|
||||
// sm: 12,
|
||||
// md: 8,
|
||||
// lg: 8,
|
||||
// xl: 6,
|
||||
// xxl: 4,
|
||||
// };
|
||||
// // const cardHeight = 120;
|
||||
// // const pagination = useCardPagination();
|
||||
// const list = ref<Array<any>>([]);
|
||||
//
|
||||
// for (let i = 0; i < 270; i++) {
|
||||
// list.value.push({
|
||||
// id: i + 1,
|
||||
// name: `名称 ${i + 1}`,
|
||||
// host: `192.168.1.${i}`
|
||||
// });
|
||||
// }
|
||||
// pagination.total = 270;
|
||||
|
||||
// 创建卡片
|
||||
const CreateCard = {
|
||||
props: ['cardHeight', 'createCardDescription'],
|
||||
setup(props: { cardHeight: any; createCardDescription: any; }) {
|
||||
return () => {
|
||||
return h(compile(`
|
||||
<a-card class="general-card card-list-item create-card"
|
||||
:style="{ height: '${props.cardHeight}px' }"
|
||||
:body-style="{ height: '100%' }"
|
||||
:bordered="false"
|
||||
:hoverable="true">
|
||||
<div class="create-card-body">
|
||||
<icon-plus class="create-card-body-icon" />
|
||||
<span class="create-card-body-text">${props.createCardDescription}</span>
|
||||
</div>
|
||||
</a-card>
|
||||
`));
|
||||
};
|
||||
}
|
||||
pagination.total = 270;
|
||||
const add = () => {
|
||||
console.log('add');
|
||||
};
|
||||
const search = () => {
|
||||
console.log('search');
|
||||
};
|
||||
const reset = () => {
|
||||
console.log('reset');
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@header-info-height: 48px;
|
||||
@header-handler-height: 48px;
|
||||
@top-height: 16 + @header-info-height + @header-handler-height + 12px;
|
||||
|
||||
.card-list-layout {
|
||||
|
||||
&-header {
|
||||
margin: -16px -16px 0 -16px;
|
||||
padding: 16px 16px 12px 16px;
|
||||
position: fixed;
|
||||
background: var(--color-fill-2);
|
||||
z-index: 999;
|
||||
height: @top-height;
|
||||
transition: none;
|
||||
|
||||
&-wrapper {
|
||||
background: var(--color-bg-4);
|
||||
padding: 0 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&-body {
|
||||
margin-top: @top-height - 16px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.disabled-col {
|
||||
cursor: not-allowed;
|
||||
|
||||
.card-list-item-disabled {
|
||||
pointer-events: none;
|
||||
opacity: .5;
|
||||
background: var(--color-bg-1);
|
||||
}
|
||||
}
|
||||
|
||||
.card-list-info {
|
||||
height: @header-info-height;
|
||||
border-bottom: 1px solid var(--color-border-2);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.card-list-handler {
|
||||
height: @header-handler-height;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.header-icon-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 27px;
|
||||
padding: 6px;
|
||||
color: var(--color-text-2);
|
||||
background: var(--color-fill-2);
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
border: 1px solid transparent;
|
||||
transition: background-color 0.1s cubic-bezier(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
.header-icon-wrapper:hover {
|
||||
background: var(--color-fill-3);
|
||||
}
|
||||
|
||||
:deep(.create-card) {
|
||||
|
||||
&-body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
&-icon {
|
||||
font-size: 18px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
&-text {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.empty-list-card {
|
||||
|
||||
&-body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&-body-creatable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -8,25 +8,10 @@
|
||||
@openUpdateConfig="(e) => config.open(e)" />
|
||||
<!-- 列表-卡片 -->
|
||||
<host-card-list v-else
|
||||
:create-card-position="'head'"
|
||||
:card-height="180"
|
||||
:list="list"
|
||||
:pagination="pagination"
|
||||
ref="card"
|
||||
@openAdd="() => modal.openAdd()"
|
||||
@openUpdate="(e) => modal.openUpdate(e)"
|
||||
@openUpdateConfig="(e) => config.open(e)">
|
||||
|
||||
<template #title="{ record }">
|
||||
{{ record.name }}
|
||||
</template>
|
||||
<template #extra="{ index }">
|
||||
{{ index }}
|
||||
</template>
|
||||
<template #card="{ record }">
|
||||
{{ record }}
|
||||
</template>
|
||||
</host-card-list>
|
||||
ref="card" />
|
||||
<!-- @openAdd="() => modal.openAdd()"-->
|
||||
<!-- @openUpdate="(e) => modal.openUpdate(e)"-->
|
||||
<!-- @openUpdateConfig="(e) => config.open(e)" />-->
|
||||
<!-- 添加修改模态框 -->
|
||||
<host-form-modal ref="modal"
|
||||
@added="() => table.addedCallback()"
|
||||
@@ -49,20 +34,6 @@
|
||||
import HostCardList from '@/views/asset/host/components/host-card-list.vue';
|
||||
import HostFormModal from './components/host-form-modal.vue';
|
||||
import HostConfigDrawer from '@/views/asset/host/components/host-config-drawer.vue';
|
||||
import { useCardPagination } from '@/types/table';
|
||||
|
||||
const pagination = useCardPagination();
|
||||
const list = ref<Array<any>>([]);
|
||||
|
||||
for (let i = 0; i < 270; i++) {
|
||||
list.value.push({
|
||||
id: i + 1,
|
||||
name: `名称 ${i + 1}`,
|
||||
host: `192.168.1.${i}`,
|
||||
disabled: i === 0
|
||||
});
|
||||
}
|
||||
pagination.total = 270;
|
||||
|
||||
const table = ref();
|
||||
const card = ref();
|
||||
|
||||
Reference in New Issue
Block a user