修改模板.

This commit is contained in:
lijiahang
2023-10-05 00:50:15 +08:00
parent 27c24a6f5a
commit 5cba137402
9 changed files with 281 additions and 144 deletions

View File

@@ -120,6 +120,10 @@ body {
color: rgb(var(--arcoblue-6));
}
.span-red {
color: rgb(var(--red-6));
}
#app {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;

View File

@@ -75,9 +75,9 @@
box-shadow: 2px 2px 12px rgba(0, 0, 0, .15);
}
.card-descriptions {
height: 100%;
overflow-y: auto;
.card-extra-icon {
font-size: 16px;
cursor: pointer;
}
.usn {

View File

@@ -25,7 +25,8 @@
<div class="card-list-handler-left">
<a-space>
<!-- 创建 -->
<div v-if="!handleVisible.disableAdd"
<div v-permission="addPermission"
v-if="!handleVisible.disableAdd"
class="header-icon-wrapper"
title="创建"
@click="emits('add')">
@@ -83,7 +84,9 @@
<a-row v-if="list.length !== 0"
:gutter="cardLayoutGutter">
<!-- 添加卡片 -->
<a-col v-if="createCardPosition === 'head'" v-bind="cardLayoutCols">
<a-col v-permission="addPermission"
v-if="createCardPosition === 'head'"
v-bind="cardLayoutCols">
<create-card :card-height="cardHeight"
:create-card-description="createCardDescription"
@click="emits('add')" />
@@ -112,12 +115,58 @@
<template #extra>
<slot name="extra" :record="item" :index="index" :key="item[key]" />
</template>
<!-- 内容 -->
<slot name="card" :record="item" :index="index" :key="item[key]" />
<!-- 内容-字段 -->
<template v-if="fieldConfig && fieldConfig.fields">
<div :class="['fields-container', fieldConfig.bodyClass]">
<template v-for="(field, index) in fieldConfig.fields">
<a-row align="center"
:style="{
'margin-bottom': fieldConfig.rowGap || '10px'
}">
<!-- 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>{{ item[field.dataIndex] }}</span>
</a-tooltip>
<template v-else>
<span>{{ 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>
</a-card>
</a-col>
<!-- 添加卡片 -->
<a-col v-if="createCardPosition === 'tail'" v-bind="cardLayoutCols">
<a-col v-permission="addPermission"
v-if="createCardPosition === 'tail'"
v-bind="cardLayoutCols">
<create-card :card-height="cardHeight"
:create-card-description="createCardDescription"
@click="emits('add')" />
@@ -128,12 +177,7 @@
<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-empty class="empty-list-card-body" description="暂无数据" />
</a-card>
</template>
</a-spin>
@@ -150,7 +194,7 @@
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/card';
import { Position, CardRecord, ColResponsiveValue, HandleVisible, CardFieldConfig } from '@/types/card';
const appStore = useAppStore();
const headerWidth = computed(() => {
@@ -189,6 +233,10 @@
type: Boolean as PropType<Boolean>,
default: () => false
},
fieldConfig: {
type: Object as PropType<CardFieldConfig>,
default: () => []
},
cardHeight: Number,
searchInputWidth: {
type: String,
@@ -206,14 +254,6 @@
type: String as PropType<Position>,
default: () => '暂无数据 点击此处进行创建'
},
emptyToCreate: {
type: Boolean,
default: () => true
},
emptyDescription: {
type: String,
default: () => '暂无数据 点击此处进行创建'
},
cardLayoutGutter: {
type: [Number, Array] as PropType<Number> |
PropType<ResponsiveValue> |
@@ -221,6 +261,10 @@
PropType<Array<ResponsiveValue>>,
default: () => [16, 16]
},
addPermission: {
type: Array as PropType<String[]>,
default: () => []
},
cardLayoutCols: {
type: Object as PropType<ColResponsiveValue>,
default: () => {
@@ -382,8 +426,34 @@
padding: 0;
}
&-body-creatable {
cursor: pointer;
}
.fields-container {
height: 100%;
overflow-y: auto;
.field-label {
color: var(--color-text-3);
word-break: break-all;
white-space: pre-wrap;
padding-right: 8px;
font-size: 14px;
font-weight: 500;
}
.field-value {
color: var(--color-text-1);
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;
}
}

View File

@@ -1,21 +1,46 @@
import { DescData, PaginationProps, ResponsiveValue } from '@arco-design/web-vue';
import { PaginationProps, ResponsiveValue } from '@arco-design/web-vue';
import { reactive } from 'vue';
/**
* 卡片字段
* 对齐方式
*/
export interface CardField {
field: string;
label: string;
render: (record: CardRecord) => string;
span?: number;
}
export type Align = 'left' | 'center' | 'right';
/**
* 创建卡片位置
*/
export type Position = 'head' | 'tail' | false;
/**
* 卡片字段配置
*/
export interface CardFieldConfig {
rowGap?: string;
bodyClass?: string;
showColon?: boolean;
labelSpan?: number;
labelOffset?: number;
labelAlign?: Align;
valueAlign?: Align;
labelClass?: string;
valueClass?: string;
fields: CardField[];
}
/**
* 卡片字段
*/
export interface CardField {
label: string;
dataIndex: string;
slotName?: string;
labelClass?: string;
valueClass?: string;
ellipsis?: boolean;
tooltip?: boolean;
}
/**
* 卡片实体
*/
@@ -72,17 +97,3 @@ export const usePagination = (): PaginationProps => {
pageSizeOptions: [12, 18, 36, 48, 96]
});
};
/**
* 转为卡片描述对象
*/
export const toCardDesc = (fields: CardField[], record: CardRecord): DescData[] => {
return fields.map(s => {
return {
field: s.field,
label: s.label,
value: s.render(record),
span: s.span || 3
};
});
};

View File

@@ -1,40 +1,72 @@
<template>
<card-list ref="cardList"
v-model:searchValue="formModel.name"
<card-list v-model:searchValue="formModel.name"
create-card-position="head"
:card-height="180"
:loading="loading"
:fieldConfig="fieldConfig"
:list="list"
:pagination="pagination"
:card-layout-cols="cardColLayout"
@add="add"
:add-permission="['asset:host:create']"
@add="emits('openAdd')"
@reset="reset"
@search="fetchTableData"
@page-change="fetchTableData">
<!-- 标题 -->
<template #title="{ record }">
{{ record.id }}
{{ record.name }}
</template>
<!-- 标题拓展 -->
<template #extra="{ index }">
{{ index }}
<!-- 编码 -->
<template #code="{ record }">
<a-tag>{{ record.code }}</a-tag>
</template>
<!-- 卡片 -->
<template #card="{ record }">
<a-descriptions class="card-descriptions"
:data="convert(record)"
:column="1">
<template #value="{ data }">
{{ data.field }}
<template v-if="data.field === 'id'">
<a-tag>{{ data.value }}</a-tag>
<!-- 地址 -->
<template #address="{ record }">
<a-tooltip content="点击复制">
<span class="host-address" @click="copy(record.address)">
<icon-copy class="mr4" />{{ record.address }}
</span>
</a-tooltip>
</template>
<!-- 标签 -->
<template #tags="{ record }">
<a-space v-if="record.tags" wrap>
<a-tag v-for="tag in record.tags"
:key="tag.id"
:color="dataColor(tag.name, tagColor)">
{{ tag.name }}
</a-tag>
</a-space>
</template>
<!-- 拓展操作 -->
<template #extra="{ record }">
<a-space>
<!-- 更多操作 -->
<a-dropdown trigger="hover">
<icon-more class="card-extra-icon" />
<template #content>
<!-- 修改 -->
<a-doption v-permission="['asset:host:update']"
@click="emits('openUpdate', record)">
<icon-edit />
修改
</a-doption>
<!-- 配置 -->
<a-doption v-permission="['asset:host:update-config']"
@click="emits('openUpdateConfig', record)">
<icon-settings />
配置
</a-doption>
<!-- 删除 -->
<a-doption class="span-red" @click="deleteRow(record.id)">
<icon-delete />
删除
</a-doption>
</template>
<template v-else>
{{ data.value }}
</template>
</template>
</a-descriptions>
</a-dropdown>
</a-space>
</template>
<!-- 左侧条件 -->
<template #leftHandle>
<span>1</span>
</template>
@@ -51,58 +83,86 @@
import { usePagination, useColLayout } from '@/types/card';
import { reactive, ref } from 'vue';
import useLoading from '@/hooks/loading';
import { resetObject } from '@/utils';
import { convert } from '../types/card.fields';
const formModel = reactive({
name: undefined
});
import { dataColor, resetObject } from '@/utils';
import fieldConfig from '../types/card.fields';
import { deleteHost, getHostPage, HostQueryRequest, HostQueryResponse } from '@/api/asset/host';
import { Message } from '@arco-design/web-vue';
import { tagColor } from '@/views/asset/host/types/const';
import useCopy from '@/hooks/copy';
const { copy } = useCopy();
const { loading, setLoading } = useLoading();
const cardColLayout = useColLayout();
const pagination = usePagination();
const list = ref<Array<any>>([]);
const list = ref<HostQueryResponse[]>([]);
const emits = defineEmits(['openAdd', 'openUpdate', 'openUpdateConfig']);
// 切换页码
const fetchTableData = (page = 1, limit = pagination.pageSize, form = formModel) => {
console.log(page, limit, form);
setLoading(true);
setTimeout(() => {
try {
const t = 90;
for (let i = 0; i < t; i++) {
list.value.push({
id: i + 1,
name: `名称 ${i + 1}`,
address: `192.168.1.${i}`,
disabled: i === 0
});
}
pagination.total = t;
pagination.current = page;
pagination.pageSize = limit;
setLoading(false);
} catch (e) {
} finally {
setLoading(false);
}
}, 300);
};
fetchTableData();
const formModel = reactive<HostQueryRequest>({
name: undefined,
extra: true
});
const add = () => {
console.log('add');
// 删除当前行
const deleteRow = async (id: number) => {
try {
setLoading(true);
// 调用删除接口
await deleteHost(id);
Message.success('删除成功');
// 重新加载数据
await fetchTableData();
} catch (e) {
} finally {
setLoading(false);
}
};
// 添加后回调
const addedCallback = () => {
fetchTableData();
};
// 更新后回调
const updatedCallback = () => {
fetchTableData();
};
defineExpose({
addedCallback, updatedCallback
});
// 重置条件
const reset = () => {
console.log('reset');
resetObject(formModel);
fetchTableData();
};
// 加载数据
const doFetchTableData = async (request: HostQueryRequest) => {
try {
setLoading(true);
const { data } = await getHostPage(request);
list.value = data.rows;
pagination.total = data.total;
pagination.current = request.page;
pagination.pageSize = request.limit;
} catch (e) {
} finally {
setLoading(false);
}
};
// 切换页码
const fetchTableData = (page = 1, limit = pagination.pageSize, form = formModel) => {
doFetchTableData({ page, limit, ...form });
};
fetchTableData();
</script>
<style scoped lang="less">
.host-address {
cursor: pointer;
color: rgb(var(--arcoblue-6))
}
</style>

View File

@@ -25,7 +25,7 @@
<a-input v-model="formModel.address" placeholder="请输入主机地址" allow-clear />
</a-form-item>
<!-- 主机标签 -->
<a-form-item field="tags" label="主机地址" label-col-flex="50px">
<a-form-item field="tags" label="主机标签" label-col-flex="50px">
<tag-multi-selector v-model="formModel.tags"
ref="tagSelector"
:allowCreate="false"
@@ -94,7 +94,7 @@
</a-tooltip>
</template>
<!-- 标签 -->
<template #tag="{ record }">
<template #tags="{ record }">
<a-space v-if="record.tags">
<a-tag v-for="tag in record.tags"
:key="tag.id"
@@ -279,7 +279,6 @@
margin: 0 4px;
}
.host-favorite-choice {
color: rgb(var(--yellow-6));

View File

@@ -8,10 +8,10 @@
@openUpdateConfig="(e) => config.open(e)" />
<!-- 列表-卡片 -->
<host-card-list v-else
ref="card" />
<!-- @openAdd="() => modal.openAdd()"-->
<!-- @openUpdate="(e) => modal.openUpdate(e)"-->
<!-- @openUpdateConfig="(e) => config.open(e)" />-->
ref="card"
@openAdd="() => modal.openAdd()"
@openUpdate="(e) => modal.openUpdate(e)"
@openUpdateConfig="(e) => config.open(e)" />
<!-- 添加修改模态框 -->
<host-form-modal ref="modal"
@added="() => table.addedCallback()"

View File

@@ -1,30 +1,23 @@
import { CardField, CardRecord, toCardDesc } from '@/types/card';
export const fields = [
{
field: 'id',
label: 'id',
render: r => r.id,
}, {
field: 'name',
label: '主机名称',
render: r => r.name,
}, {
field: 'code',
label: '主机编码',
render: r => 'code',
}, {
field: 'address',
label: '主机地址',
render: r => 'address',
}, {
field: 'tag',
label: '标签',
render: r => 'tag',
},
] as CardField[];
export const convert = (record: CardRecord) => {
return toCardDesc(fields, record);
};
import { CardField, CardFieldConfig } from '@/types/card';
export const fieldConfig = {
rowGap: '10px',
labelSpan: 8,
fields: [
{
label: '主机编码',
dataIndex: 'code',
slotName: 'code',
}, {
label: '主机地址',
dataIndex: 'address',
slotName: 'address',
tooltip: true,
}, {
label: '主机标签',
dataIndex: 'tags',
slotName: 'tags',
},
] as CardField[]
} as CardFieldConfig;
export default fieldConfig;

View File

@@ -24,9 +24,9 @@ const columns = [
slotName: 'address',
width: 260
}, {
title: '标签',
dataIndex: 'tag',
slotName: 'tag',
title: '主机标签',
dataIndex: 'tags',
slotName: 'tags',
align: 'left',
}, {
title: '操作',