refactor: 重构 card 组件.
This commit is contained in:
@@ -100,6 +100,12 @@
|
|||||||
box-shadow: 2px 2px 12px rgba(0, 0, 0, .15);
|
box-shadow: 2px 2px 12px rgba(0, 0, 0, .15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-list-item-disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: .5;
|
||||||
|
background: var(--color-bg-1);
|
||||||
|
}
|
||||||
|
|
||||||
.card-extra-icon {
|
.card-extra-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
v-model:page-size="(pagination as PaginationProps).pageSize"
|
v-model:page-size="(pagination as PaginationProps).pageSize"
|
||||||
v-bind="pagination"
|
v-bind="pagination"
|
||||||
:auto-adjust="false"
|
:auto-adjust="false"
|
||||||
@change="page => emits('pageChange', page, (pagination as PaginationProps).pageSize)"
|
@change="page => emits('emitter', HeaderEmitter.PAGE_CHANGE, page, (pagination as PaginationProps).pageSize)"
|
||||||
@page-size-change="limit => emits('pageChange', 1, limit)" />
|
@page-size-change="limit => emits('emitter', HeaderEmitter.PAGE_CHANGE, 1, limit)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 操作部分 -->
|
<!-- 操作部分 -->
|
||||||
@@ -25,10 +25,10 @@
|
|||||||
<a-space>
|
<a-space>
|
||||||
<!-- 创建 -->
|
<!-- 创建 -->
|
||||||
<div v-permission="addPermission"
|
<div v-permission="addPermission"
|
||||||
v-if="!handleVisible.disableAdd"
|
v-if="!handleVisible?.disableAdd"
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
class="click-icon-wrapper card-header-icon-wrapper"
|
||||||
title="创建"
|
title="创建"
|
||||||
@click="emits('add')">
|
@click="emits('emitter', HeaderEmitter.ADD)">
|
||||||
<icon-plus />
|
<icon-plus />
|
||||||
</div>
|
</div>
|
||||||
<!-- 左侧侧操作槽位 -->
|
<!-- 左侧侧操作槽位 -->
|
||||||
@@ -41,24 +41,24 @@
|
|||||||
<!-- 右侧操作槽位 -->
|
<!-- 右侧操作槽位 -->
|
||||||
<slot name="rightHandle" />
|
<slot name="rightHandle" />
|
||||||
<!-- 搜索框 -->
|
<!-- 搜索框 -->
|
||||||
<div v-if="!handleVisible.disableSearchInput"
|
<div v-if="!handleVisible?.disableSearchInput"
|
||||||
class="header-input-wrapper"
|
class="header-input-wrapper"
|
||||||
:style="{width: searchInputWidth}">
|
:style="{width: searchInputWidth}">
|
||||||
<a-input v-model="searchValueRef"
|
<a-input v-model="searchValueRef"
|
||||||
:placeholder="searchInputPlaceholder"
|
:placeholder="searchInputPlaceholder as string"
|
||||||
size="small"
|
size="small"
|
||||||
allow-clear
|
allow-clear
|
||||||
@input="e => emits('update:searchValue', e)"
|
@input="e => emits('emitter', HeaderEmitter.UPDATE_SEARCH_VALUE, e)"
|
||||||
@change="e => emits('update:searchValue', e)"
|
@change="e => emits('emitter', HeaderEmitter.UPDATE_SEARCH_VALUE, e)"
|
||||||
@keyup.enter="emits('search')" />
|
@keyup.enter="emits('emitter', HeaderEmitter.SEARCH)" />
|
||||||
</div>
|
</div>
|
||||||
<!-- 过滤条件 -->
|
<!-- 过滤条件 -->
|
||||||
<a-popover position="br" trigger="click" content-class="card-filter-wrapper">
|
<a-popover position="br" trigger="click" content-class="card-filter-wrapper">
|
||||||
<div v-if="!handleVisible.disableFilter"
|
<div v-if="!handleVisible?.disableFilter"
|
||||||
ref="filterRef"
|
ref="filterRef"
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
class="click-icon-wrapper card-header-icon-wrapper"
|
||||||
title="选择过滤条件">
|
title="选择过滤条件">
|
||||||
<a-badge :count="filterCount" :dot-style="{zoom: '.75'}" :offset="[9, -6]">
|
<a-badge :count="filterCount as number" :dot-style="{zoom: '.75'}" :offset="[9, -6]">
|
||||||
<icon-filter />
|
<icon-filter />
|
||||||
</a-badge>
|
</a-badge>
|
||||||
</div>
|
</div>
|
||||||
@@ -75,17 +75,17 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-popover>
|
</a-popover>
|
||||||
<!-- 搜索 -->
|
<!-- 搜索 -->
|
||||||
<div v-if="!handleVisible.disableSearch"
|
<div v-if="!handleVisible?.disableSearch"
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
class="click-icon-wrapper card-header-icon-wrapper"
|
||||||
title="搜索"
|
title="搜索"
|
||||||
@click="emits('search')">
|
@click="emits('emitter', HeaderEmitter.SEARCH)">
|
||||||
<icon-search />
|
<icon-search />
|
||||||
</div>
|
</div>
|
||||||
<!-- 重置 -->
|
<!-- 重置 -->
|
||||||
<div v-if="!handleVisible.disableReset"
|
<div v-if="!handleVisible?.disableReset"
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
class="click-icon-wrapper card-header-icon-wrapper"
|
||||||
title="重置"
|
title="重置"
|
||||||
@click="emits('reset')">
|
@click="emits('emitter', HeaderEmitter.RESET)">
|
||||||
<icon-refresh />
|
<icon-refresh />
|
||||||
</div>
|
</div>
|
||||||
</a-space>
|
</a-space>
|
||||||
@@ -104,13 +104,19 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PaginationProps } from '@arco-design/web-vue';
|
import type { PaginationProps } from '@arco-design/web-vue';
|
||||||
import type { CardProps } from '../types/props';
|
import type { CardProps } from '../types/props';
|
||||||
import { useAppStore } from '@/store';
|
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
|
import { useAppStore } from '@/store';
|
||||||
import { triggerMouseEvent } from '@/utils';
|
import { triggerMouseEvent } from '@/utils';
|
||||||
|
import { HeaderEmitter } from '../types/emits';
|
||||||
|
|
||||||
const props = defineProps<CardProps>();
|
const props = defineProps<CardProps>();
|
||||||
|
const emits = defineEmits(['emitter']);
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
const filterRef = ref();
|
||||||
|
|
||||||
|
// 头部长度 fixed 脱离了文档流 需要计算
|
||||||
const headerWidth = computed(() => {
|
const headerWidth = computed(() => {
|
||||||
const menuWidth = appStore.menu && !appStore.topMenu && !appStore.hideMenu
|
const menuWidth = appStore.menu && !appStore.topMenu && !appStore.hideMenu
|
||||||
? appStore.menuCollapse ? 48 : appStore.menuWidth
|
? appStore.menuCollapse ? 48 : appStore.menuWidth
|
||||||
@@ -118,50 +124,44 @@
|
|||||||
return `calc(100% - ${menuWidth}px)`;
|
return `calc(100% - ${menuWidth}px)`;
|
||||||
});
|
});
|
||||||
|
|
||||||
const filterRef = ref();
|
|
||||||
|
|
||||||
const searchValueRef = computed<string>({
|
const searchValueRef = computed<string>({
|
||||||
get() {
|
get() {
|
||||||
return props.searchValue as string;
|
return props.searchValue as string;
|
||||||
},
|
},
|
||||||
set(e) {
|
set(e) {
|
||||||
if (e) {
|
if (e) {
|
||||||
emits('update:searchValue', e);
|
emits('emitter', HeaderEmitter.UPDATE_SEARCH_VALUE, e);
|
||||||
} else {
|
} else {
|
||||||
emits('update:searchValue', null);
|
emits('emitter', HeaderEmitter.UPDATE_SEARCH_VALUE, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['add', 'update:searchValue', 'search',
|
|
||||||
'reset', 'pageChange', 'click', 'dblclick']);
|
|
||||||
|
|
||||||
// 重置过滤
|
// 重置过滤
|
||||||
const filterReset = () => {
|
const filterReset = () => {
|
||||||
emits('reset');
|
emits('emitter', HeaderEmitter.RESET);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 搜索
|
// 搜索
|
||||||
const filterSearch = () => {
|
const filterSearch = () => {
|
||||||
emits('search');
|
emits('emitter', HeaderEmitter.SEARCH);
|
||||||
triggerMouseEvent(filterRef);
|
triggerMouseEvent(filterRef);
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less" scoped>
|
||||||
@header-info-height: 48px;
|
body[arco-theme='dark'] .card-list-header {
|
||||||
@header-handler-height: 48px;
|
background: #29292C;
|
||||||
@top-height: 16 + @header-info-height + @header-handler-height + 12px;
|
}
|
||||||
|
|
||||||
.card-list-header {
|
.card-list-header {
|
||||||
margin: -16px -16px 0 -16px;
|
margin: -17px -16px 0 -16px;
|
||||||
padding: 16px 16px 12px 16px;
|
padding: 16px 16px 12px 16px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
// FIXME 颜色不对 文件拆了
|
|
||||||
background: var(--color-fill-2);
|
background: var(--color-fill-2);
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
height: @top-height;
|
height: var(--top-height);
|
||||||
transition: none;
|
transition: none;
|
||||||
|
|
||||||
&-wrapper {
|
&-wrapper {
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
.card-list-info {
|
.card-list-info {
|
||||||
height: @header-info-height;
|
height: var(--header-info-height);
|
||||||
border-bottom: 1px solid var(--color-border-2);
|
border-bottom: 1px solid var(--color-border-2);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -179,25 +179,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-body {
|
|
||||||
display: block;
|
|
||||||
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-handler {
|
.card-list-handler {
|
||||||
height: @header-handler-height;
|
height: var(--header-handler-height);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -212,4 +195,5 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 卡片 -->
|
||||||
|
<a-card :class="[
|
||||||
|
'card-list-item',
|
||||||
|
item.disabled === true ? 'card-list-item-disabled' : undefined,
|
||||||
|
!!cardClass ? cardClass : undefined
|
||||||
|
]"
|
||||||
|
:style="{ height: cardHeight }"
|
||||||
|
:bordered="false"
|
||||||
|
:hoverable="true"
|
||||||
|
:body-style="cardBodyStyle as Record<string, any>"
|
||||||
|
@contextmenu.prevent="() => false"
|
||||||
|
@click="emits('emitter', CardEmitter.CLICK, item, index)"
|
||||||
|
@dblclick="emits('emitter', CardEmitter.DBL_CLICK, item, index)">
|
||||||
|
<!-- 标题 -->
|
||||||
|
<template #title>
|
||||||
|
<slot name="title" />
|
||||||
|
</template>
|
||||||
|
<!-- 拓展部分 -->
|
||||||
|
<template #extra>
|
||||||
|
<slot name="extra" />
|
||||||
|
</template>
|
||||||
|
<!-- 内容-字段 -->
|
||||||
|
<template v-if="fieldConfig && fieldConfig.fields">
|
||||||
|
<div :class="['fields-container', fieldConfig.bodyClass]">
|
||||||
|
<template v-for="(field, index) in fieldConfig.fields">
|
||||||
|
<a-row :align="fieldConfig.rowAlign || field.rowAlign || 'center'"
|
||||||
|
:style="{
|
||||||
|
'margin-bottom': index !== fieldConfig.fields.length - 1 ? (fieldConfig.rowGap || '12px') : false,
|
||||||
|
'height': fieldConfig.height || field.height || 'unset',
|
||||||
|
'min-height': fieldConfig.minHeight || field.minHeight || 'unset'
|
||||||
|
}">
|
||||||
|
<!-- label -->
|
||||||
|
<a-col :span="fieldConfig.labelSpan || 8" :offset="fieldConfig.labelOffset || 0"
|
||||||
|
:style="{ 'text-align': fieldConfig.labelAlign || 'left' }"
|
||||||
|
:class="[
|
||||||
|
fieldConfig.labelClass,
|
||||||
|
field.labelClass,
|
||||||
|
'field-label'
|
||||||
|
]">
|
||||||
|
<span>{{ field.label + (fieldConfig.showColon ? ' :' : '') }}</span>
|
||||||
|
</a-col>
|
||||||
|
<!-- value -->
|
||||||
|
<a-col :span="24 - (fieldConfig.labelSpan || 8) + (fieldConfig.labelOffset || 0)"
|
||||||
|
:style="{ 'text-align': fieldConfig.valueAlign || 'left' }"
|
||||||
|
:class="[
|
||||||
|
fieldConfig.valueClass,
|
||||||
|
field.valueClass,
|
||||||
|
'field-value',
|
||||||
|
field.ellipsis ? 'field-value-ellipsis' : ''
|
||||||
|
]">
|
||||||
|
<slot :name="field.slotName" :record="item" :index="index" :key="item[key]">
|
||||||
|
<a-tooltip v-if="field.tooltip" :content="item[field.dataIndex]">
|
||||||
|
<span v-if="field.render" v-html="field.render({ record: item, index })" />
|
||||||
|
<span v-else>{{ item[field.dataIndex] }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
<template v-else>
|
||||||
|
<span v-if="field.render" v-html="field.render({ record: item, index })" />
|
||||||
|
<span v-else>{{ item[field.dataIndex] }}</span>
|
||||||
|
</template>
|
||||||
|
</slot>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 内容-自定义槽 -->
|
||||||
|
<template v-else>
|
||||||
|
<slot name="card" />
|
||||||
|
</template>
|
||||||
|
<!-- 卡片底部 -->
|
||||||
|
<slot name="cardFooter" />
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'card-item'
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { CardRecord } from '@/types/card';
|
||||||
|
import type { CardProps } from '../types/props';
|
||||||
|
import { CardEmitter } from '../types/emits';
|
||||||
|
|
||||||
|
const props = defineProps<CardProps & {
|
||||||
|
index: number,
|
||||||
|
item: CardRecord
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emits = defineEmits(['emitter']);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.fields-container {
|
||||||
|
|
||||||
|
.field-label {
|
||||||
|
color: var(--color-text-3);
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
padding-right: 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-value {
|
||||||
|
color: var(--gray-8);
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
padding-right: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-value-ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: keep-all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -21,29 +21,25 @@
|
|||||||
import type { CardProps } from '../types/props';
|
import type { CardProps } from '../types/props';
|
||||||
|
|
||||||
const props = defineProps<CardProps>();
|
const props = defineProps<CardProps>();
|
||||||
console.log(props);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less" scoped>
|
||||||
.create-card {
|
.create-card-body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
&-body {
|
&-icon {
|
||||||
width: 100%;
|
font-size: 18px;
|
||||||
height: 100%;
|
margin-bottom: 4px;
|
||||||
display: flex;
|
}
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&-icon {
|
&-text {
|
||||||
font-size: 18px;
|
user-select: none;
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-text {
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,196 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card-list-layout">
|
<div class="card-list-layout">
|
||||||
<!-- 头部部分-固定 -->
|
<!-- 头部部分-固定 -->
|
||||||
<div class="card-list-layout-header" :style="{width: headerWidth}">
|
<card-header v-bind="props"
|
||||||
<div class="card-list-layout-header-wrapper">
|
@emitter="dispatchEmitter">
|
||||||
<!-- 信息部分 -->
|
<!-- 左侧侧操作槽位 -->
|
||||||
<div class="card-list-info">
|
<template #leftHandle>
|
||||||
<!-- 路由面包屑 -->
|
<slot name="leftHandle" />
|
||||||
<breadcrumb />
|
</template>
|
||||||
<!-- 分页部分 -->
|
<!-- 右侧操作槽位 -->
|
||||||
<div class="pagination-wrapper">
|
<template #rightHandle>
|
||||||
<a-pagination v-if="pagination"
|
<slot name="rightHandle" />
|
||||||
size="mini"
|
</template>
|
||||||
v-model:current="(pagination as PaginationProps).current"
|
<!-- 过滤表单 -->
|
||||||
v-model:page-size="(pagination as PaginationProps).pageSize"
|
<template #filterContent>
|
||||||
v-bind="pagination"
|
<slot name="filterContent" />
|
||||||
:auto-adjust="false"
|
</template>
|
||||||
@change="page => emits('pageChange', page, (pagination as PaginationProps).pageSize)"
|
</card-header>
|
||||||
@page-size-change="limit => emits('pageChange', 1, limit)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 操作部分 -->
|
|
||||||
<div class="card-list-handler">
|
|
||||||
<!-- 左侧固定 -->
|
|
||||||
<div class="card-list-handler-left">
|
|
||||||
<a-space>
|
|
||||||
<!-- 创建 -->
|
|
||||||
<div v-permission="addPermission"
|
|
||||||
v-if="!handleVisible.disableAdd"
|
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
|
||||||
title="创建"
|
|
||||||
@click="emits('add')">
|
|
||||||
<icon-plus />
|
|
||||||
</div>
|
|
||||||
<!-- 左侧侧操作槽位 -->
|
|
||||||
<slot name="leftHandle" />
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
<!-- 右侧固定 -->
|
|
||||||
<div class="card-list-handler-right">
|
|
||||||
<a-space>
|
|
||||||
<!-- 右侧操作槽位 -->
|
|
||||||
<slot name="rightHandle" />
|
|
||||||
<!-- 搜索框 -->
|
|
||||||
<div v-if="!handleVisible.disableSearchInput"
|
|
||||||
class="header-input-wrapper"
|
|
||||||
:style="{width: searchInputWidth}">
|
|
||||||
<a-input v-model="searchValueRef"
|
|
||||||
:placeholder="searchInputPlaceholder"
|
|
||||||
size="small"
|
|
||||||
allow-clear
|
|
||||||
@input="e => emits('update:searchValue', e)"
|
|
||||||
@change="e => emits('update:searchValue', e)"
|
|
||||||
@keyup.enter="emits('search')" />
|
|
||||||
</div>
|
|
||||||
<!-- 过滤条件 -->
|
|
||||||
<a-popover position="br" trigger="click" content-class="card-filter-wrapper">
|
|
||||||
<div v-if="!handleVisible.disableFilter"
|
|
||||||
ref="filterRef"
|
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
|
||||||
title="选择过滤条件">
|
|
||||||
<a-badge :count="filterCount" :dot-style="{zoom: '.75'}" :offset="[9, -6]">
|
|
||||||
<icon-filter />
|
|
||||||
</a-badge>
|
|
||||||
</div>
|
|
||||||
<template #content>
|
|
||||||
<!-- 过滤表单 -->
|
|
||||||
<slot name="filterContent" />
|
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<div class="filter-bottom-container">
|
|
||||||
<a-space>
|
|
||||||
<a-button size="mini" @click="filterReset">重置</a-button>
|
|
||||||
<a-button size="mini" type="primary" @click="filterSearch">过滤</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</a-popover>
|
|
||||||
<!-- 搜索 -->
|
|
||||||
<div v-if="!handleVisible.disableSearch"
|
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
|
||||||
title="搜索"
|
|
||||||
@click="emits('search')">
|
|
||||||
<icon-search />
|
|
||||||
</div>
|
|
||||||
<!-- 重置 -->
|
|
||||||
<div v-if="!handleVisible.disableReset"
|
|
||||||
class="click-icon-wrapper card-header-icon-wrapper"
|
|
||||||
title="重置"
|
|
||||||
@click="emits('reset')">
|
|
||||||
<icon-refresh />
|
|
||||||
</div>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- 身体部分 -->
|
<!-- 身体部分 -->
|
||||||
<a-spin class="card-list-layout-body" :loading="loading">
|
<a-spin class="card-list-layout-body" :loading="loading as boolean">
|
||||||
<!-- 卡片列表 -->
|
<!-- 卡片列表 -->
|
||||||
<a-row v-if="list.length !== 0"
|
<a-row v-if="list?.length !== 0"
|
||||||
:gutter="cardLayoutGutter"
|
:gutter="cardLayoutGutter as any"
|
||||||
align="stretch">
|
align="stretch">
|
||||||
<!-- 添加卡片 -->
|
<!-- 添加卡片 -->
|
||||||
<a-col v-permission="addPermission"
|
<a-col v-permission="addPermission"
|
||||||
v-if="createCardPosition === 'head'"
|
v-if="createCardPosition === 'head'"
|
||||||
v-bind="cardLayoutCols">
|
v-bind="cardLayoutCols">
|
||||||
<create-card :card-height="cardHeight"
|
<create-card v-bind="props" @click="emits('add')" />
|
||||||
:create-card-description="createCardDescription"
|
|
||||||
@click="emits('add')" />
|
|
||||||
</a-col>
|
</a-col>
|
||||||
<!-- 数据卡片 -->
|
<!-- 数据卡片 -->
|
||||||
<a-col v-for="(item, index) in list"
|
<a-col v-for="(item, index) in list"
|
||||||
:key="item[key]"
|
:key="item[key]"
|
||||||
v-bind="cardLayoutCols"
|
v-bind="cardLayoutCols"
|
||||||
:class="{
|
:class="{ 'disabled-col': item.disabled === true }">
|
||||||
'disabled-col': item.disabled === true
|
|
||||||
}">
|
|
||||||
<!-- 右键菜单 -->
|
<!-- 右键菜单 -->
|
||||||
<a-dropdown trigger="contextMenu" alignPoint>
|
<a-dropdown trigger="contextMenu" alignPoint>
|
||||||
<!-- 卡片 -->
|
<!-- 卡片 -->
|
||||||
<a-card :class="[
|
<card-item v-bind="props"
|
||||||
'card-list-item',
|
:index="index"
|
||||||
item.disabled === true ? 'card-list-item-disabled' : undefined,
|
:item="item"
|
||||||
!!cardClass ? cardClass : undefined
|
@emitter="dispatchEmitter">
|
||||||
]"
|
<!-- 自定义插槽 -->
|
||||||
:style="{ height: cardHeight }"
|
<template v-for="slot in Object.keys($slots)" :key="slot" #[slot]>
|
||||||
:bordered="false"
|
<slot :name="slot" :record="item" :index="index" :key="item[key]" />
|
||||||
:hoverable="true"
|
|
||||||
:body-style="cardBodyStyle"
|
|
||||||
@contextmenu.prevent="() => false"
|
|
||||||
@click="emits('click', item, index)"
|
|
||||||
@dblclick="emits('dblclick', item, index)">
|
|
||||||
<!-- 标题 -->
|
|
||||||
<template #title>
|
|
||||||
<slot name="title" :record="item" :index="index" :key="item[key]" />
|
|
||||||
</template>
|
</template>
|
||||||
<!-- 拓展部分 -->
|
</card-item>
|
||||||
<template #extra>
|
|
||||||
<slot name="extra" :record="item" :index="index" :key="item[key]" />
|
|
||||||
</template>
|
|
||||||
<!-- 内容-字段 -->
|
|
||||||
<template v-if="fieldConfig && fieldConfig.fields">
|
|
||||||
<div :class="['fields-container', fieldConfig.bodyClass]">
|
|
||||||
<template v-for="(field, index) in fieldConfig.fields">
|
|
||||||
<a-row :align="fieldConfig.rowAlign || field.rowAlign || 'center'"
|
|
||||||
:style="{
|
|
||||||
'margin-bottom': index !== fieldConfig.fields.length - 1 ? (fieldConfig.rowGap || '12px') : false,
|
|
||||||
'height': fieldConfig.height || field.height || 'unset',
|
|
||||||
'min-height': fieldConfig.minHeight || field.minHeight || 'unset'
|
|
||||||
}">
|
|
||||||
<!-- label -->
|
|
||||||
<a-col :span="fieldConfig.labelSpan || 8" :offset="fieldConfig.labelOffset || 0"
|
|
||||||
:style="{
|
|
||||||
'text-align': fieldConfig.labelAlign || 'left'
|
|
||||||
}"
|
|
||||||
:class="[fieldConfig.labelClass,
|
|
||||||
field.labelClass,
|
|
||||||
'field-label'
|
|
||||||
]">
|
|
||||||
<span>{{ field.label + (fieldConfig.showColon ? ' :' : '') }}</span>
|
|
||||||
</a-col>
|
|
||||||
<!-- value -->
|
|
||||||
<a-col :span="24 - (fieldConfig.labelSpan || 8) + (fieldConfig.labelOffset || 0)"
|
|
||||||
:style="{
|
|
||||||
'text-align': fieldConfig.valueAlign || 'left'
|
|
||||||
}"
|
|
||||||
:class="[fieldConfig.valueClass,
|
|
||||||
field.valueClass,
|
|
||||||
'field-value',
|
|
||||||
field.ellipsis ? 'field-value-ellipsis' : ''
|
|
||||||
]">
|
|
||||||
<slot :name="field.slotName" :record="item" :index="index" :key="item[key]">
|
|
||||||
<a-tooltip v-if="field.tooltip" :content="item[field.dataIndex]">
|
|
||||||
<span v-if="field.render" v-html="field.render({ record: item, index })" />
|
|
||||||
<span v-else>{{ item[field.dataIndex] }}</span>
|
|
||||||
</a-tooltip>
|
|
||||||
<template v-else>
|
|
||||||
<span v-if="field.render" v-html="field.render({ record: item, index })" />
|
|
||||||
<span v-else>{{ item[field.dataIndex] }}</span>
|
|
||||||
</template>
|
|
||||||
</slot>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!-- 内容-自定义槽 -->
|
|
||||||
<template v-else>
|
|
||||||
<slot name="card" :record="item" :index="index" :key="item[key]" />
|
|
||||||
</template>
|
|
||||||
<!-- 卡片底部 -->
|
|
||||||
<slot name="cardFooter" :record="item" :index="index" :key="item[key]" />
|
|
||||||
</a-card>
|
|
||||||
<!-- 右键菜单 -->
|
<!-- 右键菜单 -->
|
||||||
<template v-if="contextMenu" #content>
|
<template v-if="contextMenu" #content>
|
||||||
<slot name="contextMenu" :record="item" :index="index" :key="item[key]" />
|
<slot name="contextMenu" :record="item" :index="index" :key="item[key]" />
|
||||||
@@ -199,11 +53,9 @@
|
|||||||
</a-col>
|
</a-col>
|
||||||
<!-- 添加卡片 -->
|
<!-- 添加卡片 -->
|
||||||
<a-col v-permission="addPermission"
|
<a-col v-permission="addPermission"
|
||||||
v-show="createCardPosition === 'tail'"
|
v-if="createCardPosition === 'tail'"
|
||||||
v-bind="cardLayoutCols">
|
v-bind="cardLayoutCols">
|
||||||
<create-card :card-height="cardHeight"
|
<create-card v-bind="props" @click="emits('add')" />
|
||||||
:create-card-description="createCardDescription"
|
|
||||||
@click="emits('add')" />
|
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
<!-- 空列表 -->
|
<!-- 空列表 -->
|
||||||
@@ -223,281 +75,69 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { CSSProperties, PropType } from 'vue';
|
import CreateCard from './components/create-card.vue';
|
||||||
import type { PaginationProps, ResponsiveValue } from '@arco-design/web-vue';
|
import CardHeader from './components/card-header.vue';
|
||||||
import type { CardRecord, ColResponsiveValue, HandleVisible, CardFieldConfig, CardPosition } from '@/types/card';
|
import CardItem from './components/card-item.vue';
|
||||||
import { compile, computed, h, ref } from 'vue';
|
import { Emitter } from './types/emits';
|
||||||
import { useAppStore } from '@/store';
|
import { CardProps } from './types/props';
|
||||||
import { triggerMouseEvent } from '@/utils';
|
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const emits = defineEmits(Emitter);
|
||||||
const headerWidth = computed(() => {
|
|
||||||
const menuWidth = appStore.menu && !appStore.topMenu && !appStore.hideMenu
|
|
||||||
? appStore.menuCollapse ? 48 : appStore.menuWidth
|
|
||||||
: 0;
|
|
||||||
return `calc(100% - ${menuWidth}px)`;
|
|
||||||
});
|
|
||||||
|
|
||||||
const filterRef = ref();
|
const props = withDefaults(defineProps<CardProps>(), {
|
||||||
|
key: 'id',
|
||||||
const searchValueRef = computed<string>({
|
pagination: false,
|
||||||
get() {
|
loading: false,
|
||||||
return props.searchValue as string;
|
cardHeight: '100%',
|
||||||
},
|
contextMenu: true,
|
||||||
set(e) {
|
filterCount: 0,
|
||||||
if (e) {
|
searchInputWidth: '200px',
|
||||||
emits('update:searchValue', e);
|
searchValue: '',
|
||||||
} else {
|
createCardDescription: '点击此处进行创建',
|
||||||
emits('update:searchValue', null);
|
createCardPosition: 'head',
|
||||||
}
|
addPermission: () => [],
|
||||||
}
|
cardLayoutGutter: () => [16, 16],
|
||||||
});
|
cardLayoutCols: () => {
|
||||||
|
return {
|
||||||
const emits = defineEmits(['add', 'update:searchValue', 'search',
|
span: 6
|
||||||
'reset', 'pageChange', 'click', 'dblclick']);
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
key: {
|
|
||||||
type: String,
|
|
||||||
default: 'id'
|
|
||||||
},
|
|
||||||
pagination: {
|
|
||||||
type: [Object, Boolean] as PropType<PaginationProps | boolean>,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
loading: {
|
|
||||||
type: Boolean as PropType<Boolean>,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
fieldConfig: {
|
|
||||||
type: Object as PropType<CardFieldConfig>,
|
|
||||||
default: []
|
|
||||||
},
|
|
||||||
cardHeight: {
|
|
||||||
type: String,
|
|
||||||
default: '100%'
|
|
||||||
},
|
|
||||||
cardClass: String,
|
|
||||||
cardBodyStyle: Object as PropType<CSSProperties>,
|
|
||||||
contextMenu: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
filterCount: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
searchInputPlaceholder: String,
|
|
||||||
searchInputWidth: {
|
|
||||||
type: String,
|
|
||||||
default: '200px'
|
|
||||||
},
|
|
||||||
searchValue: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
createCardDescription: {
|
|
||||||
type: String,
|
|
||||||
default: '点击此处进行创建'
|
|
||||||
},
|
|
||||||
createCardPosition: {
|
|
||||||
type: String as PropType<CardPosition>,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
addPermission: {
|
|
||||||
type: Array as PropType<String[]>,
|
|
||||||
default: []
|
|
||||||
},
|
|
||||||
cardLayoutGutter: {
|
|
||||||
type: [Number, Object, Array] as PropType<Number | ResponsiveValue | Array<Number> | 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="card-list-item create-card"
|
|
||||||
:style="{ height: '${props.cardHeight}' }"
|
|
||||||
: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>
|
|
||||||
`));
|
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
};
|
handleVisible: () => {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
list: () => []
|
||||||
|
});
|
||||||
|
|
||||||
// 重置过滤
|
// 调度事件
|
||||||
const filterReset = () => {
|
const dispatchEmitter = (event: string, ...args: any) => {
|
||||||
emits('reset');
|
emits(event, ...args);
|
||||||
};
|
|
||||||
|
|
||||||
// 搜索
|
|
||||||
const filterSearch = () => {
|
|
||||||
emits('search');
|
|
||||||
triggerMouseEvent(filterRef);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less">
|
||||||
@header-info-height: 48px;
|
|
||||||
@header-handler-height: 48px;
|
|
||||||
@top-height: 16 + @header-info-height + @header-handler-height + 12px;
|
|
||||||
|
|
||||||
.card-list-layout {
|
.card-list-layout {
|
||||||
|
--header-info-height: 48px;
|
||||||
&-header {
|
--header-handler-height: 48px;
|
||||||
margin: -16px -16px 0 -16px;
|
--top-height: calc(16px + var(--header-info-height) + var(--header-handler-height) + 12px);
|
||||||
padding: 16px 16px 12px 16px;
|
|
||||||
position: fixed;
|
|
||||||
// FIXME 颜色不对 文件拆了
|
|
||||||
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 {
|
&-body {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: @top-height - 16px;
|
margin-top: calc(var(--top-height) - 16px);
|
||||||
padding-top: 4px;
|
padding-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disabled-col {
|
.disabled-col {
|
||||||
cursor: not-allowed;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-bottom-container {
|
.empty-list-card-body {
|
||||||
|
height: calc(var(--top-height) + 258px);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
align-items: center;
|
||||||
}
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
:deep(.create-card) {
|
padding: 0;
|
||||||
|
|
||||||
&-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: calc(100vh - @top-height - 140px);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fields-container {
|
|
||||||
|
|
||||||
.field-label {
|
|
||||||
color: var(--color-text-3);
|
|
||||||
word-break: break-all;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
padding-right: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-value {
|
|
||||||
color: var(--gray-8);
|
|
||||||
word-break: break-all;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
padding-right: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
.field-value.field-value-ellipsis {
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
word-break: keep-all;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
20
orion-ops-ui/src/components/view/card-list/types/emits.ts
Normal file
20
orion-ops-ui/src/components/view/card-list/types/emits.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// 头部事件
|
||||||
|
export const HeaderEmitter = {
|
||||||
|
ADD: 'add',
|
||||||
|
UPDATE_SEARCH_VALUE: 'update:searchValue',
|
||||||
|
SEARCH: 'search',
|
||||||
|
RESET: 'reset',
|
||||||
|
PAGE_CHANGE: 'pageChange'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 卡片事件
|
||||||
|
export const CardEmitter = {
|
||||||
|
CLICK: 'click',
|
||||||
|
DBL_CLICK: 'dblclick'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 事件
|
||||||
|
export const Emitter = [
|
||||||
|
...Object.values(HeaderEmitter),
|
||||||
|
...Object.values(CardEmitter),
|
||||||
|
];
|
||||||
@@ -8,7 +8,7 @@ export interface CardProps {
|
|||||||
pagination?: PaginationProps | boolean;
|
pagination?: PaginationProps | boolean;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
fieldConfig?: CardFieldConfig;
|
fieldConfig?: CardFieldConfig;
|
||||||
cardHeight: string;
|
cardHeight?: string;
|
||||||
cardClass?: string;
|
cardClass?: string;
|
||||||
cardBodyStyle?: CSSProperties;
|
cardBodyStyle?: CSSProperties;
|
||||||
contextMenu?: boolean;
|
contextMenu?: boolean;
|
||||||
@@ -17,38 +17,10 @@ export interface CardProps {
|
|||||||
searchInputWidth?: string;
|
searchInputWidth?: string;
|
||||||
searchValue?: string;
|
searchValue?: string;
|
||||||
createCardDescription?: string;
|
createCardDescription?: string;
|
||||||
createCardPosition?: CardPosition | boolean;
|
createCardPosition?: CardPosition;
|
||||||
addPermission?: Array<string>;
|
addPermission?: Array<string>;
|
||||||
cardLayoutGutter?: Number | ResponsiveValue | Array<Number> | Array<ResponsiveValue>;
|
cardLayoutGutter?: Number | ResponsiveValue | Array<Number> | Array<ResponsiveValue>;
|
||||||
cardLayoutCols?: ColResponsiveValue;
|
cardLayoutCols?: ColResponsiveValue;
|
||||||
handleVisible?: HandleVisible;
|
handleVisible?: HandleVisible;
|
||||||
list?: Array<CardRecord>;
|
list?: Array<CardRecord>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义默认 props
|
|
||||||
export const cardDefaultProps = () => {
|
|
||||||
return {
|
|
||||||
key: 'id',
|
|
||||||
pagination: false,
|
|
||||||
loading: false,
|
|
||||||
cardHeight: '100%',
|
|
||||||
contextMenu: true,
|
|
||||||
filterCount: 0,
|
|
||||||
searchInputWidth: '200px',
|
|
||||||
searchValue: '',
|
|
||||||
createCardDescription: '点击此处进行创建',
|
|
||||||
createCardPosition: false,
|
|
||||||
addPermission: () => [],
|
|
||||||
cardLayoutGutter: () => [16, 16],
|
|
||||||
cardLayoutCols: () => {
|
|
||||||
return {
|
|
||||||
span: 6
|
|
||||||
};
|
|
||||||
},
|
|
||||||
handleVisible: () => {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
list: () => []
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<card-list v-model:searchValue="formModel.searchValue"
|
<card-list v-model:searchValue="formModel.searchValue"
|
||||||
search-input-placeholder="输入 id / 名称 / 用户名"
|
search-input-placeholder="输入 id / 名称 / 用户名"
|
||||||
create-card-position="head"
|
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:fieldConfig="fieldConfig"
|
:fieldConfig="fieldConfig"
|
||||||
:list="list"
|
:list="list"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<card-list v-model:searchValue="formModel.searchValue"
|
<card-list v-model:searchValue="formModel.searchValue"
|
||||||
search-input-placeholder="输入 id / 名称"
|
search-input-placeholder="输入 id / 名称"
|
||||||
create-card-position="head"
|
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:fieldConfig="fieldConfig"
|
:fieldConfig="fieldConfig"
|
||||||
:list="list"
|
:list="list"
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<card-list v-model:searchValue="formModel.searchValue"
|
<card-list v-model:searchValue="formModel.searchValue"
|
||||||
search-input-placeholder="输入 id / 名称 / 编码 / 地址"
|
search-input-placeholder="输入 id / 名称 / 编码 / 地址"
|
||||||
create-card-position="head"
|
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:fieldConfig="fieldConfig"
|
:fieldConfig="fieldConfig"
|
||||||
:list="list"
|
:list="list"
|
||||||
|
|||||||
Reference in New Issue
Block a user