From 254816a712847b099184d84ca8631a50fb32f39e Mon Sep 17 00:00:00 2001
From: wujingjing <gersonwu@qq.com>
Date: 星期一, 03 三月 2025 15:24:09 +0800
Subject: [PATCH] 初步对接

---
 customer_list/common/static/fonts/ywiconfont/iconfont.ttf             |    0 
 src/api/ai/chat.ts                                                    |    2 
 customer_list/common/static/fonts/ywiconfont/iconfont.woff            |    0 
 src/api/attach/index.ts                                               |    6 
 src/components/layout/AHMContainer.vue                                |    2 
 src/components/chat/Chat.vue                                          |   19 ++-
 src/components/chat/components/playBar/businessTable/search/index.vue |    6 
 src/components/chat/components/playBar/PlayBar.vue                    |   19 ++
 src/components/chat/components/playBar/hook/useUploadFile.ts          |   46 ++++--
 customer_list/common/static/fonts/ywiconfont/iconfont.css             |   14 +
 customer_list/common/static/fonts/ywiconfont/iconfont.woff2           |    0 
 src/components/chat/components/playBar/businessTable/index.vue        |  204 +++++++++++++++++++++++++++++-----
 12 files changed, 248 insertions(+), 70 deletions(-)

diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.css b/customer_list/common/static/fonts/ywiconfont/iconfont.css
index b4ed7c8..bae2fb0 100644
--- a/customer_list/common/static/fonts/ywiconfont/iconfont.css
+++ b/customer_list/common/static/fonts/ywiconfont/iconfont.css
@@ -1,8 +1,8 @@
 @font-face {
   font-family: "ywifont"; /* Project id 4655417 */
-  src: url('iconfont.woff2?t=1740909922081') format('woff2'),
-       url('iconfont.woff?t=1740909922081') format('woff'),
-       url('iconfont.ttf?t=1740909922081') format('truetype');
+  src: url('iconfont.woff2?t=1740972827582') format('woff2'),
+       url('iconfont.woff?t=1740972827582') format('woff'),
+       url('iconfont.ttf?t=1740972827582') format('truetype');
 }
 
 .ywifont {
@@ -13,6 +13,14 @@
   -moz-osx-font-smoothing: grayscale;
 }
 
+.ywicon-TXTtubiao:before {
+  content: "\e64d";
+}
+
+.ywicon-csv:before {
+  content: "\e64b";
+}
+
 .ywicon-fujian:before {
   content: "\e88a";
 }
diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.ttf b/customer_list/common/static/fonts/ywiconfont/iconfont.ttf
index 9ecc5c9..c8a65de 100644
--- a/customer_list/common/static/fonts/ywiconfont/iconfont.ttf
+++ b/customer_list/common/static/fonts/ywiconfont/iconfont.ttf
Binary files differ
diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.woff b/customer_list/common/static/fonts/ywiconfont/iconfont.woff
index 034dfcf..3b6b673 100644
--- a/customer_list/common/static/fonts/ywiconfont/iconfont.woff
+++ b/customer_list/common/static/fonts/ywiconfont/iconfont.woff
Binary files differ
diff --git a/customer_list/common/static/fonts/ywiconfont/iconfont.woff2 b/customer_list/common/static/fonts/ywiconfont/iconfont.woff2
index 3fd5b69..dfc1138 100644
--- a/customer_list/common/static/fonts/ywiconfont/iconfont.woff2
+++ b/customer_list/common/static/fonts/ywiconfont/iconfont.woff2
Binary files differ
diff --git a/src/api/ai/chat.ts b/src/api/ai/chat.ts
index 7b4d155..1e37ade 100644
--- a/src/api/ai/chat.ts
+++ b/src/api/ai/chat.ts
@@ -267,7 +267,7 @@
 			params: {},
 			data: params,
 			headers: {
-				'Content-Type': 'application/x-www-form-urlencoded',
+				'Content-Type': 'multipart/form-data',
 			},
 			...extraData,
 		},
diff --git a/src/api/attach/index.ts b/src/api/attach/index.ts
index 6c7deaf..17e6a54 100644
--- a/src/api/attach/index.ts
+++ b/src/api/attach/index.ts
@@ -3,14 +3,14 @@
 export const getAttachTableList = () => {
 	return request({
 		url: '/attach/get_attach_table_list',
-		method: 'get',
+		method: 'POST',
 	});
 };
 
 export const queryAttachTableRecords = (params: any) => {
 	return request({
 		url: '/attach/query_attach_table_records',
-		method: 'get',
-		params,
+		method: 'POST',
+		data: params,
 	});
 };
diff --git a/src/components/chat/Chat.vue b/src/components/chat/Chat.vue
index 86d78ed..1878d17 100644
--- a/src/components/chat/Chat.vue
+++ b/src/components/chat/Chat.vue
@@ -142,10 +142,10 @@
 		raw_mode: roomConfig.value?.[currentRouteId]?.isAnswerByLLM ?? false,
 		...judgeParams,
 	} as any;
-	const formDataParams = toFormData(params);
-	for (const item of attachFileList.value) {
-		formDataParams.append('files', item.file);
+	if(businessTableData.value?.length > 0) {
+		params.tables = JSON.stringify(businessTableData.value);
 	}
+	
 	// if (!position) {
 	// 	const loadingInstance = ElLoadingService({
 	// 		text: '鑾峰彇浣嶇疆涓�...',
@@ -170,7 +170,10 @@
 		params.sample_id = currentSampleId;
 		currentSampleId = '';
 	}
-
+	const formDataParams = toFormData(params);
+	for (const item of attachFileList.value) {
+		formDataParams.append('files', item.file);
+	}
 	let lastTimestamp = new Date().getTime();
 	questionRes = {};
 	let lastIsResult = false;
@@ -190,7 +193,7 @@
 			return isEmpty;
 		};
 		questionStreamByPost(
-			params,
+			formDataParams,
 			(chunkRes) => {
 				Logger.info('chunk response锛歕n\n' + JSON.stringify(chunkRes));
 				if (chunkRes.mode === 'result') {
@@ -380,12 +383,15 @@
 	const content = parseContent(questionRes, true);
 	return content;
 };
-
+const playBarRef = useCompRef(PlayBar);
+const businessTableData = computed(() => playBarRef.value?.businessTableData ?? []);
 const clearMessageContent = () =>
 	(messageContent.value = {
 		type: AnswerType.Text,
 		values: '',
 	});
+	playBarRef.value?.clearFileList();
+	playBarRef.value?.clearBusinessTable();
 
 let currentSampleId = '';
 
@@ -595,7 +601,6 @@
 	messageContent.value.values = content;
 };
 //#endregion
-const playBarRef = useCompRef(PlayBar);
 //鐢ㄦ埛闂璁剧疆涓哄父鐢ㄨ
 const setCommonPhraseClick = (item) => {
 	playBarRef.value.addPhrase(item);
diff --git a/src/components/chat/components/playBar/PlayBar.vue b/src/components/chat/components/playBar/PlayBar.vue
index 020ec46..021966b 100644
--- a/src/components/chat/components/playBar/PlayBar.vue
+++ b/src/components/chat/components/playBar/PlayBar.vue
@@ -86,7 +86,10 @@
 						</el-button>
 						<div class="flex-items-center gap-2">
 							<el-tooltip placement="top" content="鍏宠仈涓氬姟琛ㄦ牸">
-								<div class="cursor-pointer size-[38px] relative !z-10 rounded flex-center hover:bg-[#f2f2f2]" @click="openBusinessTable">
+								<div
+									class="cursor-pointer size-[38px] relative !z-10 rounded flex-center hover:bg-[#f2f2f2]"
+									@click="openBusinessTable"
+								>
 									<span class="ywifont ywicon-biaoge !text-[24px]"></span>
 								</div>
 							</el-tooltip>
@@ -129,9 +132,7 @@
 				ref="commonPhraseRef"
 				@updateInput="updateInputValue"
 			/>
-			<BusinessTable
-				v-model="businessTableIsShow"
-			/>
+			<BusinessTable v-model="businessTableIsShow" @submit="submitBusinessTable" />
 		</div>
 	</div>
 </template>
@@ -229,13 +230,21 @@
 	pastTarget: inputRef as any,
 });
 
+const businessTableData = ref([]);
+const submitBusinessTable = (data) => {
+	businessTableData.value = data;
+};
+
+const clearBusinessTable = () => {
+	businessTableData.value = [];
+};
 //#region ====================== 涓氬姟琛ㄦ牸 ======================
 const businessTableIsShow = ref(false);
 const openBusinessTable = () => {
 	businessTableIsShow.value = true;
 };
 //#endregion
-defineExpose({ addPhrase, showSyncTip, attachFileList });
+defineExpose({ addPhrase, showSyncTip, attachFileList, clearFileList, businessTableData, clearBusinessTable });
 </script>
 <style scoped lang="scss">
 @use './index.scss';
diff --git a/src/components/chat/components/playBar/businessTable/index.vue b/src/components/chat/components/playBar/businessTable/index.vue
index 696efef..427474e 100644
--- a/src/components/chat/components/playBar/businessTable/index.vue
+++ b/src/components/chat/components/playBar/businessTable/index.vue
@@ -1,12 +1,19 @@
 <template>
-	<el-dialog :destroy-on-close="true" v-model="dialogIsShow" width="70%" :close-on-click-modal="false" @closed="closeDialog">
+	<el-dialog
+		class="limit-height"
+		:destroy-on-close="true"
+		v-model="dialogIsShow"
+		width="70%"
+		:close-on-click-modal="false"
+		@closed="closeDialog"
+	>
 		<template #header>
 			<div style="color: #fff">
 				<SvgIcon name="ele-Document" :size="16" style="margin-right: 3px; display: inline; vertical-align: middle" />
 				<span>涓氬姟琛ㄥ叧鑱�</span>
 			</div>
 		</template>
-		<AHMContainer type="card">
+		<AHMContainer type="card" class="h100" v-loading="submitLoading">
 			<template #aside>
 				<!-- 鐩綍鏍� -->
 				<LeftTreeByMgr
@@ -20,7 +27,7 @@
 					}"
 					defaultExpandAll
 					:treedata="listTreeData"
-					title-name="鍦烘櫙鍒楄〃"
+					title-name="闄勪欢琛�"
 					:show-more-operate="false"
 					:show-add="false"
 					:current-node-key="currentListID"
@@ -32,7 +39,7 @@
 			<template #header>
 				<el-form ref="queryFormRef" :inline="true" class="relative">
 					<el-form-item :label="item.title" prop="title" v-for="item in filterColumns as any" :key="item.name">
-						<TableSearch v-model="item.value" :filter="item.filter" @input="debounceSearch(item)" />
+						<TableSearch v-model="item.values" :filter="item.filter" @input="debounceSearch()" />
 					</el-form-item>
 				</el-form>
 			</template>
@@ -49,7 +56,14 @@
 							highlight-current-row
 							@sort-change="handleSortChange"
 						>
-							<el-table-column v-for="item in tableColumns" :prop="item.name" :label="item.title" show-overflow-tooltip>
+							<el-table-column
+								v-for="item in tableColumns"
+								:prop="item.name"
+								sortable="custom"
+								:key="item.name"
+								:label="item.title"
+								show-overflow-tooltip
+							>
 							</el-table-column>
 						</el-table>
 					</div>
@@ -81,8 +95,29 @@
 const closeDialog = () => {
 	dialogIsShow.value = false;
 };
-const submitFormValue = () => {
-	emit('submit', tableData.value);
+const submitLoading = ref(false);
+const getSubmitData = async () => {
+	submitLoading.value = true;
+	await getUnGetData().finally(() => {
+		submitLoading.value = false;
+	});
+	const tables =  listTreeData.value.map((item) => {
+		return {
+			title: item.title,
+			columns: item.columns.map((item) => {
+				return item.title;
+			}),
+			values: item.tableData.map((item) => {
+				return Object.values(item);
+			}),
+		};
+	});
+
+	return tables;
+};
+const submitFormValue = async () => {
+	const data = await getSubmitData();
+	emit('submit', data);
 	dialogIsShow.value = false;
 };
 //#region ====================== 宸︿晶鏍戞暟鎹紝tree init ======================
@@ -104,7 +139,7 @@
 				return {
 					...item,
 					// 鍒濆鏌ヨ鍊�
-					value: '',
+					values: [''],
 				};
 			});
 		}
@@ -112,31 +147,47 @@
 
 	return treeData;
 });
+/**
+ * 璁板綍 orderMap
+ */
+const setOrderMap = (node) => {
+	if (!node.orderMap) {
+		node.orderMap = new Map();
+	}
+};
+
 const handleClickNode = (data) => {
 	nextTick(() => {
 		leftTreeRef.value?.treeRef.setCurrentKey(data.id);
 	});
 	currentNode.value = data;
+	setOrderMap(data);
 	getTableData();
 };
 const getListTreeData = async () => {
-	const res = await attachApi.getAttachTableList();
+	treeLoading.value = true;
+	const res = await attachApi.getAttachTableList().finally(() => {
+		treeLoading.value = false;
+	});
 	listData.value = res.tables || [];
 	const firstListTreeNode = listTreeData.value[0];
 	if (firstListTreeNode) {
 		handleClickNode(firstListTreeNode);
 	} else {
-		tableData.value = [];
 		currentNode.value = null;
 	}
 };
 //#endregion
 //#region ====================== 鎸囨爣绠$悊琛ㄦ牸鏁版嵁锛宼able init ======================
 const tableLoading = ref(false);
-const tableData = ref([]);
+const tableData = computed(() => {
+	return currentNode.value?.tableData || [];
+});
 const isDragStatus = ref(false);
 
-const tableColumns = ref([]);
+const tableColumns = computed(() => {
+	return currentNode.value?.columns || [];
+});
 const getTableData = async () => {
 	// allTableData.value = (res.values || []).map((item) => {
 	// 	item.create_time = item.create_time?.slice(0, 10);
@@ -146,10 +197,21 @@
 	// 	const len = getLenById(allTableData.value, value.id, value);
 	// 	value.title = `${value.title} (${len})`;
 	// });
-	tableColumns.value = currentNode.value.columns;
+	if (!currentNode.value.tableData) {
+		handleSearchInput();
+	}
 };
 //#endregion
-const indexMapItem = computed(() => {
+
+const getIndexMapItem = (columns) => {
+	return new Map<number, any>(
+		columns.map((item, index) => {
+			return [index, item];
+		})
+	);
+};
+
+const indexMapItem = computed<Map<number, any>>(() => {
 	return new Map(
 		tableColumns.value.map((item, index) => {
 			return [index, item];
@@ -157,41 +219,111 @@
 	);
 });
 //#region ====================== 鏌ヨ ======================
-const handleSearchInput = async (item) => {
-	const params = {
-		id: currentNode.value.id,
-	} as any;
+const getFilterColumns = (node) => {
+	return node?.columns?.filter((item) => item.filter) as any[];
+};
+const filterColumns = computed(() => {
+	return getFilterColumns(currentNode.value);
+});
 
-	if (filterColumns.value && filterColumns.value.length) {
-		params.filter = filterColumns.value.map((item) => {
+const getSearchParams = (node) => {
+	const params = {
+		id: node.id,
+	} as any;
+	const filterColumns = getFilterColumns(node);
+	if (filterColumns && filterColumns.length) {
+		params.filter = filterColumns.map((item) => {
 			return {
 				col: item.name,
 				filter: item.filter,
-				value: item.value,
+				values: item.values,
 			};
 		});
 	}
+	setOrderMap(node);
+	const orderMap = node.orderMap;
+	const orderList = Array.from(orderMap.entries()).map(([key, value]) => {
+		return {
+			col: key,
+			order: value,
+		};
+	});
+	if (orderList?.length > 0) {
+		params.order = orderList;
+	}
+	return params;
+};
 
-	const res = await attachApi.queryAttachTableRecords(params);
-	tableData.value = (res.values || []).map((item, index) => {
+const parseRecordData = (res, columns) => {
+	const indexMapItem = getIndexMapItem(columns);
+	return (res.values || []).map((item, index) => {
 		const row = {} as any;
-
 		item?.forEach((item, index) => {
-			row[indexMapItem.value.get(index).name] = item;
+			row[indexMapItem.get(index).name] = item;
 		});
 		return row;
 	});
 };
 
+const handleSearchItem = async (node, prop?, order?, column?) => {
+	const params = getSearchParams(node);
+	// 淇涓哄綋鍓嶈淇敼鐨� order
+	if (prop) {
+		// const foundItem = params.order.find((item) => item.col === prop);
+		// if (foundItem) {
+		// 	foundItem.order = order;
+		// }
+		// 鎺掑簭鍙細鏈変竴涓瓧娈�
+		params.order = [
+			{
+				col: prop,
+				order: order,
+			},
+		];
+	}
+	tableLoading.value = true;
+	const res = await attachApi.queryAttachTableRecords(params).finally(() => {
+		tableLoading.value = false;
+	});
+	if (prop) {
+		const orderMap = node.orderMap;
+		orderMap.clear();
+		orderMap.set(prop, order);
+		column.order = getEleOrder(order);
+	}
+	node.tableData = parseRecordData(res, tableColumns.value);
+};
+
+const handleSearchInput = async (prop?, order?, column?) => {
+	handleSearchItem(currentNode.value, prop, order, column);
+};
+
+const getUnGetData = async () => {
+	const getDataPromiseList = [];
+	for (const item of listTreeData.value) {
+		if (!item.tableData) {
+			getDataPromiseList.push(handleSearchItem(item));
+		}
+	}
+	// 绛夊緟鎵�鏈夋暟鎹幏鍙栧畬鎴�
+	await Promise.all(getDataPromiseList);
+};
+
 const debounceSearch = debounce(handleSearchInput, 400);
 //#endregion
-
-const filterColumns = computed(() => {
-	return tableColumns.value.filter((item) => item.filter) as any[];
-});
-const orderMap = new Map();
+const getEleOrder = (order) => {
+	if (order === 'DESC') {
+		return 'descending';
+	} else if (order === 'ASC') {
+		return 'ascending';
+	} else {
+		return '';
+	}
+};
 
 const handleSortChange = ({ column, prop, order }) => {
+	setOrderMap(currentNode.value);
+	const orderMap = currentNode.value.orderMap;
 	// 鎭㈠鍘熺姸锛屾洿鏂板悗鍐嶆樉绀烘帓搴忕姸鎬�
 	const curOrder = orderMap.get(prop) ?? null;
 	column.order = curOrder;
@@ -204,6 +336,7 @@
 	} else {
 		sendOrder = '';
 	}
+	handleSearchInput(prop, sendOrder, column);
 };
 
 watch(
@@ -230,4 +363,15 @@
 		font-size: 14px;
 	}
 }
+
+:deep(.el-dialog__body) {
+	height: calc(90vh - 111px) !important;
+}
+</style>
+<style lang="scss">
+.limit-height {
+	.el-dialog__body {
+		height: calc(90vh - 111px) !important;
+	}
+}
 </style>
diff --git a/src/components/chat/components/playBar/businessTable/search/index.vue b/src/components/chat/components/playBar/businessTable/search/index.vue
index 2ba0974..fce0fd3 100644
--- a/src/components/chat/components/playBar/businessTable/search/index.vue
+++ b/src/components/chat/components/playBar/businessTable/search/index.vue
@@ -3,7 +3,7 @@
 		<el-input
 			v-if="filter === 'like'"
 			@input="(value) => input(value)"
-			v-model="modelValue"
+			v-model="modelValue[0]"
 			style="width: 226.4px"
 			clearable
 		/>
@@ -14,8 +14,8 @@
 const props = defineProps(['filter']);
 const emit = defineEmits(['input']);
 const modelValue = defineModel({
-	type: String,
-	default: '',
+	type: Array<string>,
+	default: [''],
 });
 
 const input = (value) => {
diff --git a/src/components/chat/components/playBar/hook/useUploadFile.ts b/src/components/chat/components/playBar/hook/useUploadFile.ts
index 14f2943..912c6c0 100644
--- a/src/components/chat/components/playBar/hook/useUploadFile.ts
+++ b/src/components/chat/components/playBar/hook/useUploadFile.ts
@@ -6,8 +6,8 @@
 	pastTarget: Ref<HTMLElement | null>;
 };
 
-export type FileType = 'doc' | 'docx' | 'pdf' | 'md' | 'xls' | 'xlsx' | 'png' | 'jpg' | 'jpeg' | 'gif' | 'json';
-export type FileGroupType = 'word' | 'pdf' | 'excel' | 'image' | 'json' | 'md';
+export type FileType = 'doc' | 'docx' | 'pdf' | 'md' | 'xls' | 'xlsx' | 'png' | 'jpg' | 'jpeg' | 'gif' | 'json' | 'txt' | 'csv';
+export type FileGroupType = 'word' | 'pdf' | 'excel' | 'image' | 'json' | 'md' | 'csv' | 'txt';
 export type UploadFile = {
 	name: string;
 	type: FileType;
@@ -24,6 +24,10 @@
 		case 'doc':
 		case 'docx':
 			return 'word';
+		case 'csv':
+			return 'csv';
+		case 'txt':
+			return 'txt';
 
 		case 'md':
 			return 'md';
@@ -52,6 +56,10 @@
 			return 'pdf';
 		case 'excel':
 			return 'excel';
+		case 'csv':
+			return 'csv';
+		case 'txt':
+			return 'txt';
 
 		case 'json':
 			return 'json';
@@ -70,6 +78,10 @@
 			return 'text-red-400';
 		case 'excel':
 			return 'text-green-400';
+		case 'csv':
+			return 'text-green-500';
+		case 'txt':
+			return 'text-cyan-400';
 
 		case 'json':
 			return 'text-yellow-400';
@@ -79,12 +91,13 @@
 			return '';
 	}
 };
-
+// const supportFileType = ['doc', 'docx', 'md', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif', 'json', 'pdf'];
+const supportFileType = ['csv', 'txt'];
+const acceptFiles = [].join(',')
 export const useUploadFile = (options: UseUploadFileOptions) => {
-	const supportFileType = ['doc', 'docx', 'md', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif', 'json', 'pdf'];
 	const attachFileList = ref<UploadFile[]>([]);
 
-	const parseFiles = (files:FileList) => {
+	const parseFiles = (files: FileList) => {
 		const filterFiles: UploadFile[] = [];
 		for (const file of files) {
 			const suffix = file.name.split('.').pop() as FileType;
@@ -114,7 +127,7 @@
 			}
 		}
 		attachFileList.value.push(...filterFiles);
-	}
+	};
 
 	/**
 	 * 瑙f瀽绮樿创鏉挎枃浠�
@@ -124,7 +137,7 @@
 		event.stopPropagation();
 		const data = event.clipboardData || window.clipboardData;
 		const files = data.files as FileList;
-		parseFiles(files)
+		parseFiles(files);
 	};
 
 	const clearFileList = () => {
@@ -132,22 +145,21 @@
 	};
 	const {
 		files,
-		open:openFileDialog,
-		reset:resetOpenFileDialog,
+		open: openFileDialog,
+		reset: resetOpenFileDialog,
 		onChange: onPickFileChange,
 	} = useFileDialog({
 		accept:
-			'application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/markdown,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,image/png,image/jpeg,image/gif,application/json,application/pdf', // Set to accept only image files
-			reset:true
+			'text/csv,text/plain', // Only accept csv and txt files
+		reset: true,
 	});
 
-
-	const openFileClick = () =>{
+	const openFileClick = () => {
 		openFileDialog();
-	}
+	};
 	onPickFileChange((files) => {
-		if(!files) return;
-		parseFiles(files)
+		if (!files) return;
+		parseFiles(files);
 	});
 	const deleteIndexFile = (index) => {
 		const file = attachFileList.value[index];
@@ -164,6 +176,6 @@
 		attachFileList,
 		clearFileList,
 		deleteIndexFile,
-		openFileClick
+		openFileClick,
 	};
 };
diff --git a/src/components/layout/AHMContainer.vue b/src/components/layout/AHMContainer.vue
index d8fc4b7..bbebd64 100644
--- a/src/components/layout/AHMContainer.vue
+++ b/src/components/layout/AHMContainer.vue
@@ -8,7 +8,7 @@
 			<slot v-else name="aside"></slot>
 		</el-col>
 		<el-col :span="20" :xs="24" class="flex-column h100">
-			<el-card class="yw-layout-card yw-layout-header" v-if="type === 'card'" shadow="hover" :body-style="{ paddingBottom: '0' }">
+			<el-card class="yw-layout-card yw-layout-header flex-0" v-if="type === 'card'" shadow="hover" :body-style="{ paddingBottom: '0' }">
 				<slot name="header"> </slot>
 			</el-card>
 			<slot v-else name="header"> </slot>

--
Gitblit v1.9.3