|
|
|
@ -56,6 +56,16 @@ const searchResultList = ref<ExcelRowData[]>([]); |
|
|
|
/** 搜索结果加载状态 */ |
|
|
|
/** 搜索结果加载状态 */ |
|
|
|
const searchResultLoading = ref(false); |
|
|
|
const searchResultLoading = ref(false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 数据列表分页参数 */ |
|
|
|
|
|
|
|
const searchResultPagination = ref({ |
|
|
|
|
|
|
|
current: 1, |
|
|
|
|
|
|
|
size: 10, |
|
|
|
|
|
|
|
total: 0 |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** 已展开的卡片ID集合 */ |
|
|
|
|
|
|
|
const expandedCardIds = ref<Set<string>>(new Set()); |
|
|
|
|
|
|
|
|
|
|
|
/** 保存的搜索关键字 - 用于在 autocomplete 选择后恢复原始关键字进行匹配 */ |
|
|
|
/** 保存的搜索关键字 - 用于在 autocomplete 选择后恢复原始关键字进行匹配 */ |
|
|
|
const savedKeyword = ref(''); |
|
|
|
const savedKeyword = ref(''); |
|
|
|
|
|
|
|
|
|
|
|
@ -265,7 +275,9 @@ const handleClearSearch = () => { |
|
|
|
batchPagination.value.current = 1; |
|
|
|
batchPagination.value.current = 1; |
|
|
|
loadBatchList(); |
|
|
|
loadBatchList(); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// 数据列表 Tab:用空关键字刷新当前批次数据 |
|
|
|
// 数据列表 Tab:重置分页和展开状态 |
|
|
|
|
|
|
|
searchResultPagination.value.current = 1; |
|
|
|
|
|
|
|
expandedCardIds.value.clear(); |
|
|
|
loadSearchResults('', currentBatchId.value); |
|
|
|
loadSearchResults('', currentBatchId.value); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
@ -383,6 +395,12 @@ const viewBatchData = (batch: ExcelRowData) => { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
currentBatchId.value = batch.batchId; |
|
|
|
currentBatchId.value = batch.batchId; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 【数据赋值】重置分页和展开状态 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
searchResultPagination.value.current = 1; |
|
|
|
|
|
|
|
expandedCardIds.value.clear(); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* 【数据赋值】加载该批次的所有数据 |
|
|
|
* 【数据赋值】加载该批次的所有数据 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -399,6 +417,7 @@ const viewBatchData = (batch: ExcelRowData) => { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
const loadSearchResults = async (keyword: string = '', batchId?: string) => { |
|
|
|
const loadSearchResults = async (keyword: string = '', batchId?: string) => { |
|
|
|
searchResultLoading.value = true; |
|
|
|
searchResultLoading.value = true; |
|
|
|
|
|
|
|
expandedCardIds.value.clear(); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -408,8 +427,8 @@ const loadSearchResults = async (keyword: string = '', batchId?: string) => { |
|
|
|
const res: any = await searchExcelDataPage({ |
|
|
|
const res: any = await searchExcelDataPage({ |
|
|
|
keyword, |
|
|
|
keyword, |
|
|
|
batchId, |
|
|
|
batchId, |
|
|
|
current: 1, |
|
|
|
current: searchResultPagination.value.current, |
|
|
|
size: 100 // 获取更多数据用于卡片展示 |
|
|
|
size: searchResultPagination.value.size |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (res?.records) { |
|
|
|
if (res?.records) { |
|
|
|
@ -417,6 +436,7 @@ const loadSearchResults = async (keyword: string = '', batchId?: string) => { |
|
|
|
* 【数据赋值】保存搜索结果 |
|
|
|
* 【数据赋值】保存搜索结果 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
searchResultList.value = res.records; |
|
|
|
searchResultList.value = res.records; |
|
|
|
|
|
|
|
searchResultPagination.value.total = res.total || 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
console.error('加载搜索结果失败:', error); |
|
|
|
console.error('加载搜索结果失败:', error); |
|
|
|
@ -561,6 +581,44 @@ const handleBatchSizeChange = (size: number) => { |
|
|
|
loadBatchList(); |
|
|
|
loadBatchList(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ==================== 数据列表分页和展开/折叠 ==================== |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 切换卡片展开/折叠状态 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
const toggleCardExpand = (id: string) => { |
|
|
|
|
|
|
|
if (expandedCardIds.value.has(id)) { |
|
|
|
|
|
|
|
expandedCardIds.value.delete(id); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
expandedCardIds.value.add(id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
expandedCardIds.value = new Set(expandedCardIds.value); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 判断卡片是否展开 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
const isCardExpanded = (id: string) => expandedCardIds.value.has(id); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 数据列表分页变化 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
const handleDataPageChange = (page: number) => { |
|
|
|
|
|
|
|
searchResultPagination.value.current = page; |
|
|
|
|
|
|
|
expandedCardIds.value.clear(); |
|
|
|
|
|
|
|
loadSearchResults(searchKeyword.value, currentBatchId.value); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 数据列表每页条数变化 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
const handleDataSizeChange = (size: number) => { |
|
|
|
|
|
|
|
searchResultPagination.value.size = size; |
|
|
|
|
|
|
|
searchResultPagination.value.current = 1; |
|
|
|
|
|
|
|
expandedCardIds.value.clear(); |
|
|
|
|
|
|
|
loadSearchResults(searchKeyword.value, currentBatchId.value); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// ==================== 删除操作 ==================== |
|
|
|
// ==================== 删除操作 ==================== |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -791,14 +849,14 @@ loadBatchList(); |
|
|
|
<div class="tab-label"> |
|
|
|
<div class="tab-label"> |
|
|
|
<el-icon><DataLine /></el-icon> |
|
|
|
<el-icon><DataLine /></el-icon> |
|
|
|
<span>数据列表</span> |
|
|
|
<span>数据列表</span> |
|
|
|
<el-badge :value="searchResultList.length" type="success" /> |
|
|
|
<el-badge :value="searchResultPagination.total" type="success" /> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 搜索结果提示 --> |
|
|
|
<!-- 搜索结果提示 --> |
|
|
|
<div class="search-tip" v-if="searchKeyword"> |
|
|
|
<div class="search-tip" v-if="searchKeyword"> |
|
|
|
<el-icon><InfoFilled /></el-icon> |
|
|
|
<el-icon><InfoFilled /></el-icon> |
|
|
|
当前显示:<strong>{{ searchKeyword }}</strong> 相关的 {{ searchResultList.length }} 条数据 |
|
|
|
当前显示:<strong>{{ searchKeyword }}</strong> 相关的 {{ searchResultPagination.total }} 条数据 |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 数据列表 - 卡片布局 --> |
|
|
|
<!-- 数据列表 - 卡片布局 --> |
|
|
|
@ -808,17 +866,33 @@ loadBatchList(); |
|
|
|
v-for="(item, index) in searchResultList" |
|
|
|
v-for="(item, index) in searchResultList" |
|
|
|
:key="item.id || index" |
|
|
|
:key="item.id || index" |
|
|
|
class="data-card" |
|
|
|
class="data-card" |
|
|
|
@click="viewDataDetail(item)" |
|
|
|
:class="{ 'is-expanded': isCardExpanded(item.id) }" |
|
|
|
> |
|
|
|
> |
|
|
|
<div class="data-card-header"> |
|
|
|
<!-- 卡片头部 - 始终显示,点击可展开/折叠 --> |
|
|
|
|
|
|
|
<div class="data-card-header" @click="toggleCardExpand(item.id)"> |
|
|
|
<div class="data-source"> |
|
|
|
<div class="data-source"> |
|
|
|
<el-icon class="source-icon"><Document /></el-icon> |
|
|
|
<el-icon class="source-icon"><Document /></el-icon> |
|
|
|
<span class="source-name clickable" @click.stop="handleFilePreview(item)">{{ item.fileName }}</span> |
|
|
|
<span class="source-name clickable" @click.stop="handleFilePreview(item)">{{ item.fileName }}</span> |
|
|
|
<el-tag size="small" type="info">{{ item.sheetName }}</el-tag> |
|
|
|
<el-tag size="small" type="info">{{ item.sheetName }}</el-tag> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="header-right"> |
|
|
|
<span class="row-number">第 {{ item.rowIndex }} 行</span> |
|
|
|
<span class="row-number">第 {{ item.rowIndex }} 行</span> |
|
|
|
|
|
|
|
<el-button |
|
|
|
|
|
|
|
link |
|
|
|
|
|
|
|
size="small" |
|
|
|
|
|
|
|
class="expand-btn" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
{{ isCardExpanded(item.id) ? '收起' : '展开' }} |
|
|
|
|
|
|
|
<el-icon> |
|
|
|
|
|
|
|
<ArrowUp v-if="isCardExpanded(item.id)" /> |
|
|
|
|
|
|
|
<ArrowDown v-else /> |
|
|
|
|
|
|
|
</el-icon> |
|
|
|
|
|
|
|
</el-button> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="data-card-body"> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 卡片展开内容 - 折叠/展开 --> |
|
|
|
|
|
|
|
<div class="data-card-body" v-show="isCardExpanded(item.id)"> |
|
|
|
<div class="row-data-list"> |
|
|
|
<div class="row-data-list"> |
|
|
|
<el-tooltip |
|
|
|
<el-tooltip |
|
|
|
v-for="(field, fIdx) in getCardPreview(item)" |
|
|
|
v-for="(field, fIdx) in getCardPreview(item)" |
|
|
|
@ -838,17 +912,32 @@ loadBatchList(); |
|
|
|
</el-tooltip> |
|
|
|
</el-tooltip> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 卡片底部 - 始终显示 --> |
|
|
|
<div class="data-card-footer"> |
|
|
|
<div class="data-card-footer"> |
|
|
|
<span class="batch-name" v-if="item.batchName"> |
|
|
|
<span class="batch-name" v-if="item.batchName"> |
|
|
|
<el-icon><Folder /></el-icon> |
|
|
|
<el-icon><Folder /></el-icon> |
|
|
|
{{ item.batchName }} |
|
|
|
{{ item.batchName }} |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
<el-button type="primary" link size="small"> |
|
|
|
<el-button type="primary" link size="small" @click.stop="viewDataDetail(item)"> |
|
|
|
查看详情 |
|
|
|
查看详情 |
|
|
|
<el-icon><View /></el-icon> |
|
|
|
<el-icon><View /></el-icon> |
|
|
|
</el-button> |
|
|
|
</el-button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 分页组件 --> |
|
|
|
|
|
|
|
<div class="pagination-wrapper" v-if="searchResultList.length > 0"> |
|
|
|
|
|
|
|
<el-pagination |
|
|
|
|
|
|
|
v-model:current-page="searchResultPagination.current" |
|
|
|
|
|
|
|
v-model:page-size="searchResultPagination.size" |
|
|
|
|
|
|
|
:page-sizes="[10, 20, 50]" |
|
|
|
|
|
|
|
:total="searchResultPagination.total" |
|
|
|
|
|
|
|
layout="total, sizes, prev, pager, next" |
|
|
|
|
|
|
|
@current-change="handleDataPageChange" |
|
|
|
|
|
|
|
@size-change="handleDataSizeChange" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-tab-pane> |
|
|
|
</el-tab-pane> |
|
|
|
</el-tabs> |
|
|
|
</el-tabs> |
|
|
|
@ -1232,6 +1321,47 @@ loadBatchList(); |
|
|
|
color: #909399; |
|
|
|
color: #909399; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 卡片展开/折叠状态 |
|
|
|
|
|
|
|
.data-card-body { |
|
|
|
|
|
|
|
max-height: 0; |
|
|
|
|
|
|
|
overflow: hidden; |
|
|
|
|
|
|
|
transition: max-height 0.3s ease-out, margin 0.3s ease-out; |
|
|
|
|
|
|
|
margin-top: 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
&.is-expanded { |
|
|
|
|
|
|
|
border-color: #409eff; |
|
|
|
|
|
|
|
box-shadow: 0 4px 16px rgba(64, 158, 255, 0.25); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.data-card-body { |
|
|
|
|
|
|
|
max-height: 1000px; |
|
|
|
|
|
|
|
margin-top: 16px; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 头部右侧区域 |
|
|
|
|
|
|
|
.header-right { |
|
|
|
|
|
|
|
display: flex; |
|
|
|
|
|
|
|
align-items: center; |
|
|
|
|
|
|
|
gap: 12px; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.row-number { |
|
|
|
|
|
|
|
font-size: 13px; |
|
|
|
|
|
|
|
color: #606266; |
|
|
|
|
|
|
|
background: #f4f4f5; |
|
|
|
|
|
|
|
padding: 4px 12px; |
|
|
|
|
|
|
|
border-radius: 12px; |
|
|
|
|
|
|
|
font-weight: 500; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.expand-btn { |
|
|
|
|
|
|
|
.el-icon { |
|
|
|
|
|
|
|
margin-left: 4px; |
|
|
|
|
|
|
|
transition: transform 0.3s ease; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ==================== 下拉列表样式 ==================== |
|
|
|
// ==================== 下拉列表样式 ==================== |
|
|
|
|