feat: 行业词云图

This commit is contained in:
renxiaodong
2025-06-20 02:07:38 -04:00
parent 2700a06578
commit 1641320847

View File

@ -26,19 +26,18 @@
<a-tag <a-tag
v-for="(tag, tagIndex) in row.tags" v-for="(tag, tagIndex) in row.tags"
:key="tagIndex" :key="tagIndex"
class="cursor-pointer"
:style="{ :style="{
fontSize: `${getFontSize(rowIndex, tagIndex)}px`, fontSize: `${getTagStyle(rowIndex, tagIndex, row.tags.length).fontSize}px`,
lineHeight: `${getLineHeight(rowIndex, tagIndex) + 10}px`, height: `${getTagStyle(rowIndex, tagIndex, row.tags.length).lineHeight}px`,
color: '#6d4cfe', color: '#6d4cfe',
backgroundColor: '#F0EDFF', backgroundColor: '#F0EDFF',
margin: '12px', margin: '0 12px 12px 0',
transition: 'all 0.3s', transition: 'all 0.3s',
paddingLeft: `${getPaddingLeft(rowIndex, tagIndex)}px`, paddingLeft: `${getPaddingLeft(rowIndex, tagIndex)}px`,
paddingRight: `${getPaddingLeft(rowIndex, tagIndex)}px`, paddingRight: `${getPaddingLeft(rowIndex, tagIndex)}px`,
paddingTop: `${getPadding(rowIndex, tagIndex)}px`, borderRadius: '32px',
paddingBottom: `${getPadding(rowIndex, tagIndex)}px`, fontWeight: 400,
borderRadius: '100px',
borderRadius: '100px',
}" }"
@mouseenter="hoverTag = tag" @mouseenter="hoverTag = tag"
@mouseleave="hoverTag = null" @mouseleave="hoverTag = null"
@ -85,30 +84,34 @@ const getIndustryTerms = async () => {
industry_id: selectedIndustry.value, industry_id: selectedIndustry.value,
time_dimension: selectedTimePeriod.value, time_dimension: selectedTimePeriod.value,
}; };
if (selectedSubCategory.value != 0) { if (selectedSubCategory.value !== 0) {
params['industry_id'] = selectedSubCategory.value; params['industry_id'] = selectedSubCategory.value;
} }
const res = await fetchindustryTerms(params); const res = await fetchindustryTerms(params);
// 这里需要根据API返回的数据结构处理成tagRows需要的格式 // 这里需要根据API返回的数据结构处理成tagRows需要的格式
tagRows.value = processTagData(res); tagRows.value = processTagData(res.slice(0, 70));
}; };
// 标签数据(按行分组) // 标签数据(按行分组)
const tagRows = ref(); const tagRows = ref();
const hoverTag = ref(null); const hoverTag = ref(null);
// 根据行列位置计算字体大小(中间最大) const lineHeightStart = [28, 52, 58, 72, 58, 52, 28]; // 7行时
const getFontSize = (rowIndex, tagIndex) => { const fontSizeStart = [12, 26, 28, 38, 28, 26, 12]; // 7行时
const centerRow = Math.floor(tagRows.value.length / 2); const stepLineHeight = 10; // 行高每步递减
const distance = Math.abs(rowIndex - centerRow); const stepFontSize = 6; // 字号每步递减
return 38 - distance * 8 + (tagIndex % 2) * 5; // 基础24px行距影响4px微调差异2px
};
const getLineHeight = (rowIndex, tagIndex) => { function getTagStyle(rowIndex, tagIndex, tagsLength) {
const centerRow = Math.floor(tagRows.value.length / 2); // 计算当前行的中间起点
const distance = Math.abs(rowIndex - centerRow); const center = Math.floor(tagsLength / 2);
return 48 - distance * 8 + (tagIndex % 2) * 5; // 基础24px行距影响4px微调差异2px 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 getPaddingLeft = (rowIndex, tagIndex) => {
const centerRow = Math.floor(tagRows.value.length / 2); const centerRow = Math.floor(tagRows.value.length / 2);
@ -124,35 +127,34 @@ const getPadding = (rowIndex, tagIndex) => {
// 处理API返回数据为tagRows格式 // 处理API返回数据为tagRows格式
const processTagData = (apiData) => { const processTagData = (apiData) => {
const totalGroups = 4; // 总组数 // 计算应该分几行最多7行
const middleIndex = Math.floor(totalGroups / 2); // 中间位置索引3 const maxRows = 7;
const chunkSize = Math.ceil(apiData.length / totalGroups); // 每组大小 const rowCount = Math.min(Math.ceil(apiData.length / 7), maxRows);
const arr = [];
// 1. 先按顺序分组 // 均分数据到rowCount行
const tempGroups = []; const baseCount = Math.floor(apiData.length / rowCount);
for (let i = 0; i < totalGroups; i++) { let remain = apiData.length % rowCount;
const start = i * chunkSize; const rows = [];
const end = start + chunkSize; let start = 0;
tempGroups.push(apiData.slice(start, end)); 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;
} }
// 2. 从中间开始,左右交替插入 // 居中分布,从中间往两侧
for (let i = 0; i < totalGroups; i++) { const result = [];
// 计算当前组应该插入的位置 const center = Math.floor(rowCount / 2);
const insertPos = i % 2 === 0 ? middleIndex + i / 2 : middleIndex - Math.ceil(i / 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' };
if (insertPos >= 0 && insertPos < totalGroups) {
arr[insertPos] = { tags: tempGroups[i], align: 'center' };
}
} }
return result;
return arr.filter(Boolean); // 移除可能的空项
}; };
</script> </script>
<style scoped> <style scoped lang="less">
/* 自定义样式 */ /* 自定义样式 */
:deep(.arco-table-th) { :deep(.arco-table-th) {
background-color: var(--color-fill-2); background-color: var(--color-fill-2);
@ -168,14 +170,29 @@ const processTagData = (apiData) => {
:deep(.arco-modal-body) { :deep(.arco-modal-body) {
padding: 0px; padding: 0px;
} }
.multi-row-tag-cloud { .multi-row-tag-cloud {
width: 100%; width: 100%;
padding: 20px; padding: 20px;
} .tag-row {
display: flex;
.tag-row { align-items: center;
display: flex; // flex-wrap: wrap;
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;
}
}
}
} }
/* 悬停放大效果 */ /* 悬停放大效果 */