Files
lingji-work-fe/src/views/components/dataEngine/hotCloud.vue

193 lines
5.9 KiB
Vue
Raw Normal View History

2025-06-16 14:42:26 +08:00
<template>
<view>
2025-06-17 11:18:39 +08:00
<topHeader ref="topHeaderRef" @search="search"></topHeader>
2025-06-16 14:42:26 +08:00
<a-space direction="vertical" style="background-color: #fff; width: 100%; padding: 24px; margin: 24px 0">
<a-space align="center">
<span>行业词云</span>
<a-popover position="tl">
<a-button type="primary" class="pop-btn">
<template #icon>
<icon-question-circle />
</template>
</a-button>
<template #content>
<p>基于xxx获取数据xxx一段文字描述该数据的获取方式和来源等xxx</p>
</template>
</a-popover>
</a-space>
<div class="multi-row-tag-cloud">
<!-- 动态生成多行标签 -->
<div
v-for="(row, rowIndex) in tagRows"
:key="rowIndex"
class="tag-row"
:style="{ justifyContent: row.align || 'center' }"
>
<a-tag
v-for="(tag, tagIndex) in row.tags"
:key="tagIndex"
:style="{
fontSize: `${getFontSize(rowIndex, tagIndex)}px`,
lineHeight: `${getLineHeight(rowIndex, tagIndex) + 10}px`,
color: '#6d4cfe',
backgroundColor: '#F0EDFF',
margin: '12px',
transition: 'all 0.3s',
paddingLeft: `${getPaddingLeft(rowIndex, tagIndex)}px`,
paddingRight: `${getPaddingLeft(rowIndex, tagIndex)}px`,
paddingTop: `${getPadding(rowIndex, tagIndex)}px`,
paddingBottom: `${getPadding(rowIndex, tagIndex)}px`,
borderRadius: '100px',
borderRadius: '100px',
}"
@mouseenter="hoverTag = tag"
@mouseleave="hoverTag = null"
>
<a-space>
<a-tooltip :content="`性价比:${Number(tag.rate * 100)}%`" position="tl">
<a-space>{{ tag.term }}</a-space>
</a-tooltip>
</a-space>
</a-tag>
</div>
</div>
</a-space>
</view>
</template>
<script setup>
import topHeader from './topHeader.vue';
import { ref, computed } from 'vue';
import { fetchindustryTerms } from '@/api/all/index';
const topHeaderRef = ref();
// 从topHeader获取统一的状态
const selectedIndustry = computed(() => topHeaderRef.value?.selectedIndustry);
const selectedSubCategory = computed(() => topHeaderRef.value?.selectedSubCategory);
const selectedTimePeriod = computed(() => topHeaderRef.value?.selectedTimePeriod);
2025-06-17 11:18:39 +08:00
// 监听筛选条件变化
watch([selectedTimePeriod, selectedSubCategory], () => {
getIndustryTerms();
});
const search = () => {
getIndustryTerms();
};
watch(selectedIndustry, () => {
selectedSubCategory.value = 0;
getIndustryTerms();
});
2025-06-16 14:42:26 +08:00
2025-06-17 11:18:39 +08:00
onMounted(() => {
getIndustryTerms();
});
2025-06-16 14:42:26 +08:00
const getIndustryTerms = async () => {
const params = {
industry_id: selectedIndustry.value,
time_dimension: selectedTimePeriod.value,
};
2025-06-17 11:18:39 +08:00
if (selectedSubCategory.value != 0) {
params['industry_id'] = selectedSubCategory.value;
}
2025-06-16 14:42:26 +08:00
const res = await fetchindustryTerms(params);
// 这里需要根据API返回的数据结构处理成tagRows需要的格式
tagRows.value = processTagData(res);
};
// 标签数据(按行分组)
const tagRows = ref();
const hoverTag = ref(null);
// 根据行列位置计算字体大小(中间最大)
const getFontSize = (rowIndex, tagIndex) => {
const centerRow = Math.floor(tagRows.value.length / 2);
const distance = Math.abs(rowIndex - centerRow);
return 38 - distance * 8 + (tagIndex % 2) * 5; // 基础24px行距影响4px微调差异2px
};
const getLineHeight = (rowIndex, tagIndex) => {
const centerRow = Math.floor(tagRows.value.length / 2);
const distance = Math.abs(rowIndex - centerRow);
return 48 - distance * 8 + (tagIndex % 2) * 5; // 基础24px行距影响4px微调差异2px
};
const getPaddingLeft = (rowIndex, tagIndex) => {
const centerRow = Math.floor(tagRows.value.length / 2);
const distance = Math.abs(rowIndex - centerRow);
return 30 - distance * 8 + (tagIndex % 2) * 5; // 基础24px行距影响4px微调差异2px
};
const getPadding = (rowIndex, tagIndex) => {
const centerRow = Math.floor(tagRows.value.length / 2);
const distance = Math.abs(rowIndex - centerRow);
return 28 - distance * 8 + (tagIndex % 2) * 5; // 基础24px行距影响4px微调差异2px
};
// 处理API返回数据为tagRows格式
const processTagData = (apiData) => {
2025-06-17 11:18:39 +08:00
const totalGroups = 4; // 总组数
2025-06-16 14:42:26 +08:00
const middleIndex = Math.floor(totalGroups / 2); // 中间位置索引3
const chunkSize = Math.ceil(apiData.length / totalGroups); // 每组大小
const arr = [];
// 1. 先按顺序分组
const tempGroups = [];
for (let i = 0; i < totalGroups; i++) {
const start = i * chunkSize;
const end = start + chunkSize;
tempGroups.push(apiData.slice(start, end));
}
// 2. 从中间开始,左右交替插入
for (let i = 0; i < totalGroups; i++) {
// 计算当前组应该插入的位置
const insertPos = i % 2 === 0 ? middleIndex + i / 2 : middleIndex - Math.ceil(i / 2);
// 确保不越界
if (insertPos >= 0 && insertPos < totalGroups) {
arr[insertPos] = { tags: tempGroups[i], align: 'center' };
}
}
return arr.filter(Boolean); // 移除可能的空项
};
</script>
<style scoped>
/* 自定义样式 */
:deep(.arco-table-th) {
background-color: var(--color-fill-2);
}
:deep(.arco-table-tr):hover {
background-color: var(--color-fill-1);
}
:deep(.arco-btn-outline) {
color: #6d4cfe !important;
border-color: #6d4cfe !important;
}
:deep(.arco-modal-body) {
padding: 0px;
}
.multi-row-tag-cloud {
width: 100%;
padding: 20px;
}
.tag-row {
display: flex;
flex-wrap: wrap;
}
/* 悬停放大效果 */
a-tag:hover {
transform: scale(1.1);
z-index: 1;
}
.pop-btn {
background: #fff !important;
border-color: #fff !important;
color: #737478 !important;
margin-left: -5px;
}
</style>