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

230 lines
6.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view>
<topHeader ref="topHeaderRef" @search="search"></topHeader>
<a-space
direction="vertical"
class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid w-100% py-0 px-20px mb-24px"
>
<div class="title-row">
<span class="title mr-4px">行业词云</span>
<a-tooltip>
<template #content>基于行业内内容提取的高频词汇</template>
<icon-question-circle size="16" class="!color-#737478" />
</a-tooltip>
</div>
<div class="multi-row-tag-cloud h-472px">
<NoData v-if="tagRows.length === 0" text="暂无数据" />
<!-- 动态生成多行标签 -->
<template v-else>
<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"
class="cursor-pointer"
:style="{
fontSize: `${getTagStyle(rowIndex, tagIndex, row.tags.length).fontSize}px`,
height: `${getTagStyle(rowIndex, tagIndex, row.tags.length).lineHeight}px`,
color: '#6d4cfe',
backgroundColor: '#F0EDFF',
margin: '0 12px 12px 0',
transition: 'all 0.3s',
paddingLeft: `${getPaddingLeft(rowIndex, tagIndex)}px`,
paddingRight: `${getPaddingLeft(rowIndex, tagIndex)}px`,
borderRadius: '32px',
fontWeight: 400,
}"
@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>
</template>
</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);
// 监听筛选条件变化
watch([selectedTimePeriod, selectedSubCategory], () => {
getIndustryTerms();
});
const search = () => {
getIndustryTerms();
};
watch(selectedIndustry, () => {
selectedSubCategory.value = 0;
getIndustryTerms();
});
onMounted(() => {
getIndustryTerms();
});
const getIndustryTerms = async () => {
const params = {
industry_id: selectedIndustry.value,
time_dimension: selectedTimePeriod.value,
};
if (selectedIndustry.value == undefined) {
return;
}
if (selectedSubCategory.value !== 0) {
params['industry_id'] = selectedSubCategory.value;
}
const res = await fetchindustryTerms(params);
if (res.code === 200) {
// 这里需要根据API返回的数据结构处理成tagRows需要的格式
tagRows.value = processTagData(res.data.slice(0, 70));
}
};
// 标签数据(按行分组)
const tagRows = ref([]);
const hoverTag = ref(null);
const lineHeightStart = [28, 52, 58, 72, 58, 52, 28]; // 7行时
const fontSizeStart = [12, 26, 28, 38, 28, 26, 12]; // 7行时
const stepLineHeight = 10; // 行高每步递减
const stepFontSize = 6; // 字号每步递减
function getTagStyle(rowIndex, tagIndex, tagsLength) {
// 计算当前行的中间起点
const center = Math.floor(tagsLength / 2);
const distance = Math.abs(tagIndex - center);
// 递减,最小值保护
const lineHeight = Math.max(lineHeightStart[rowIndex] - stepLineHeight * distance, 28);
const fontSize = Math.max(fontSizeStart[rowIndex] - stepFontSize * distance, 12);
return { fontSize, lineHeight };
}
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) => {
// 计算应该分几行最多7行
const maxRows = 7;
const rowCount = Math.min(Math.ceil(apiData.length / 7), maxRows);
// 均分数据到rowCount行
const baseCount = Math.floor(apiData.length / rowCount);
let remain = apiData.length % rowCount;
const rows = [];
let start = 0;
for (let i = 0; i < rowCount; i++) {
let count = baseCount + (remain > 0 ? 1 : 0);
if (remain > 0) remain--;
rows.push(apiData.slice(start, start + count));
start += count;
}
// 居中分布,从中间往两侧
const result = [];
const center = Math.floor(rowCount / 2);
for (let i = 0; i < rowCount; i++) {
const pos = i % 2 === 0 ? center + Math.floor(i / 2) : center - Math.ceil(i / 2);
result[pos] = { tags: rows[i], align: 'center' };
}
return result;
};
</script>
<style scoped lang="scss">
/* 自定义样式 */
: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;
align-items: center;
// flex-wrap: wrap;
:deep(.arco-tag) {
transition: all 0.3s;
border-radius: 32px;
font-weight: 400;
// min-width: 100px;
max-width: 200px;
display: flex;
justify-content: center;
&:hover {
background-color: #ffffff !important;
color: #6d4cfe !important;
box-shadow: 0px 4px 12px 0px #0000001a;
}
}
}
}
/* 悬停放大效果 */
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;
}
.title-row {
display: flex;
height: 64px;
// padding: 10px 0 2px 0;
align-items: center;
.title {
color: var(--Text-1, #211f24);
font-family: $font-family-medium;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 24px; /* 150% */
}
}
</style>