feat(图表): 优化图表组件并添加动态数据支持

- 修改Line.vue组件,修复默认值格式和优化数据反转逻辑
- 更新newsInfo.ts API,修改热门标签/行业/来源的请求参数拼接方式
- 重构LineHol.vue组件,移除硬编码数据,支持动态数据绑定和样式优化
- 在realtimeInfo页面添加7天热度统计功能,支持不同标签切换
- 改进LineHolYellow.vue组件,支持动态数据并优化图表样式
This commit is contained in:
zzp 2025-09-12 16:20:38 +08:00
parent 2e68592cf1
commit 3a29305df7
5 changed files with 151 additions and 65 deletions

View File

@ -42,15 +42,14 @@ export const getNews_cnt_d = (data: any) => {
// 热门标签某时间段内topN列表 // 热门标签某时间段内topN列表
export const getTopConceptPeriod = (data: any) => { export const getTopConceptPeriod = (data: any) => {
return request.get("/top_concept_period", data); return request.get("/top_concept_period?start_date=" + data.start_time + "&end_date=" + data.end_time + "&limit_num=" + data.limit_num, data);
}; };
// 热门行业某时间段内topN列表
// 热门标签某时间段内topN列表
export const getTopIndustryPeriod = (data: any) => { export const getTopIndustryPeriod = (data: any) => {
return request.get("/top_industry_period", data); return request.get("/top_industry_period?start_date=" + data.start_time + "&end_date=" + data.end_time + "&limit_num=" + data.limit_num, data);
}; };
// 热门标签某时间段内topN列表 // 热门标签某时间段内topN列表
export const getTopSourcePeriod = (data: any) => { export const getTopSourcePeriod = (data: any) => {
return request.get("/top_source_period", data); return request.get("/top_source_period?start_date=" + data.start_date + "&end_date=" + data.end_time + "&limit_num=" + data.limit_num, data);
}; };

View File

@ -28,7 +28,7 @@ const colorList = ["#F05040", "#696BBE", "#93CFED", "#FE9F19", "#3C74F1"];
const props = defineProps({ const props = defineProps({
data: { data: {
type: Object, type: Object,
default: () => { }, default: () => {},
}, },
}); });
@ -42,8 +42,8 @@ watch(
keys.value.push(item.key); keys.value.push(item.key);
values.value.push(item.doc_count); values.value.push(item.doc_count);
}); });
keys.value.reverse() keys.value.reverse();
values.value.reverse() values.value.reverse();
initChart(); initChart();
} }
); );

View File

@ -23,30 +23,22 @@ const props = defineProps({
}, },
}); });
watch(
() => props.data,
(newVal) => {
if (newVal) {
initChart();
}
}
);
// //
const initChart = () => { const initChart = () => {
myChart = echarts.init(chartDom.value); myChart = echarts.init(chartDom.value);
const builderJson = { const builderJson = {
all: 10887, all: 10887,
charts: { charts: {},
map: 3237,
lines: 2164,
bar: 7561,
line: 7778,
pie: 7355,
scatter: 2405,
candlestick: 1842,
radar: 2090,
heatmap: 1762,
treemap: 1593,
graph: 2060,
boxplot: 1537,
parallel: 1908,
gauge: 2107,
funnel: 1692,
sankey: 1568,
},
components: { components: {
geo: 2788, geo: 2788,
title: 9575, title: 9575,
@ -63,6 +55,16 @@ const initChart = () => {
}, },
ie: 9743, ie: 9743,
}; };
// value
const maxItem = props.data.reduce((prev, current) => {
// value
return current.value > prev.value ? current : prev;
}, props.data[0]); //
props.data.forEach((item) => {
builderJson.charts[item.content] = item.value;
});
builderJson.all = maxItem.value;
const waterMarkText = "ECHARTS"; const waterMarkText = "ECHARTS";
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
@ -76,19 +78,20 @@ const initChart = () => {
ctx.rotate(-Math.PI / 4); ctx.rotate(-Math.PI / 4);
ctx.fillText(waterMarkText, 0, 0); ctx.fillText(waterMarkText, 0, 0);
let option = { let option = {
backgroundColor: { // backgroundColor: {
type: "pattern", // type: "pattern",
image: canvas, // image: canvas,
repeat: "repeat", // repeat: "repeat",
}, // },
tooltip: {}, tooltip: {},
title: [], title: [],
grid: [ grid: [
{ {
top: 0, top: 0,
width: "90%", width: "90%",
bottom: "0%", top: "5%",
left: 0, bottom: "10%",
left: 10,
containLabel: true, containLabel: true,
}, },
], ],
@ -123,6 +126,12 @@ const initChart = () => {
position: "right", position: "right",
show: true, show: true,
}, },
itemStyle: {
color: "#52A8FF",
normal: {
borderRadius: [0, 4, 4, 0],
},
},
data: Object.keys(builderJson.charts).map(function (key) { data: Object.keys(builderJson.charts).map(function (key) {
return builderJson.charts[key]; return builderJson.charts[key];
}), }),
@ -141,8 +150,6 @@ onMounted(async () => {
// await getData(); // await getData();
// initChart(); // initChart();
// }, 5000); // }, 5000);
initChart();
}); });
</script> </script>

View File

@ -26,40 +26,77 @@ const props = defineProps({
// //
const initChart = () => { const initChart = () => {
myChart = echarts.init(chartDom.value); myChart = echarts.init(chartDom.value);
let source = [];
source.push(["score", "amount", "product"]);
props.data.forEach((item) => {
source.push([item.value, item.value, item.content]);
});
let option = { let option = {
dataset: { dataset: {
source: [ source: source,
["score", "amount", "product"], // [
[89.3, 58212, "Matcha Latte"], // ["score", "amount", "product"],
[57.1, 78254, "Milk Tea"], // [89.3, 58212, "Matcha Latte"],
[74.4, 41032, "Cheese Cocoa"], // [57.1, 78254, "Milk Tea"],
[50.1, 12755, "Cheese Brownie"], // [74.4, 41032, "Cheese Cocoa"],
[89.7, 20145, "Matcha Cocoa"], // [50.1, 12755, "Cheese Brownie"],
[68.1, 79146, "Tea"], // [89.7, 20145, "Matcha Cocoa"],
[19.6, 91852, "Orange Juice"], // [68.1, 79146, "Tea"],
[10.6, 101852, "Lemon Juice"], // [19.6, 91852, "Orange Juice"],
[32.7, 20112, "Walnut Brownie"], // [10.6, 101852, "Lemon Juice"],
], // [32.7, 20112, "Walnut Brownie"],
// ],
}, },
grid: { containLabel: true }, grid: {
xAxis: { name: "amount" }, top: 0,
yAxis: { type: "category" }, width: "90%",
visualMap: { top: "5%",
orient: "horizontal", bottom: "10%",
left: "center", left: 10,
min: 10, containLabel: true,
max: 100, },
text: ["High Score", "Low Score"], xAxis: {
// Map the score column to color splitLine: {
dimension: 0, show: false,
inRange: {
color: ["#65B581", "#FFCE34", "#FD665F"],
}, },
}, },
yAxis: {
type: "category",
axisLabel: {
interval: 0,
rotate: 30,
},
splitLine: {
show: false,
},
},
// visualMap: {
// show: false,
// orient: "horizontal",
// left: "center",
// min: 1,
// max: 100,
// text: ["High Score", "Low Score"],
// // Map the score column to color
// dimension: 0,
// inRange: {
// color: ["#65B581", "#FFCE34", "#FD665F"],
// },
// },
series: [ series: [
{ {
type: "bar", type: "bar",
label: {
position: "right",
show: true,
},
itemStyle: {
color: "#FFCE34",
normal: {
borderRadius: [0, 4, 4, 0],
},
},
encode: { encode: {
// Map the "amount" column to X axis. // Map the "amount" column to X axis.
x: "amount", x: "amount",

View File

@ -64,10 +64,10 @@
</view> </view>
<view style="background-color: white; margin-top: 40rpx"> <view style="background-color: white; margin-top: 40rpx">
<indexMenuTitle title="热度统计"></indexMenuTitle> <indexMenuTitle title="近7天热度统计"></indexMenuTitle>
<LineHol v-if="lineTabIndex === 0"></LineHol> <LineHol v-if="lineTabIndex === 0" :data="lineTopData"></LineHol>
<LineHol v-else-if="lineTabIndex === 1"></LineHol> <LineHol v-else-if="lineTabIndex === 1" :data="lineTopData"></LineHol>
<LineHolYellow v-else-if="lineTabIndex === 2"></LineHolYellow> <LineHolYellow v-else-if="lineTabIndex === 2" :data="lineTopData"></LineHolYellow>
<div style="display: flex; justify-content: center; margin-bottom: 20px; margin-top: 20px"> <div style="display: flex; justify-content: center; margin-bottom: 20px; margin-top: 20px">
<div class="tabs"> <div class="tabs">
@ -143,7 +143,18 @@ import tagicon_2 from "@/assets/zixun/tagicon_2.png";
import LoginPopup from "@/components/loginPopup/index.vue"; import LoginPopup from "@/components/loginPopup/index.vue";
import { Session } from "@/utils/storage"; import { Session } from "@/utils/storage";
import { getindustryCount, getConceptCount, getTopNews, getTopIndustry_d, getTopConcept_d, getNews_cnt_d, newsInfoScore } from "@/api/newsInfo"; import {
getindustryCount,
getConceptCount,
getTopNews,
getTopIndustry_d,
getTopConcept_d,
getNews_cnt_d,
newsInfoScore,
getTopConceptPeriod,
getTopIndustryPeriod,
getTopSourcePeriod,
} from "@/api/newsInfo";
import countTo from "@/components/count-to/vue-countTo.vue"; import countTo from "@/components/count-to/vue-countTo.vue";
import RankList from "@/components/RankList.vue"; // import RankList from "@/components/RankList.vue"; //
import InfoSummary from "@/components/InfoSummary.vue"; // import InfoSummary from "@/components/InfoSummary.vue"; //
@ -268,6 +279,36 @@ function loginOut() {
const lineTabIndex = ref(0); const lineTabIndex = ref(0);
function handleTabClick(index) { function handleTabClick(index) {
lineTabIndex.value = index; lineTabIndex.value = index;
getLineDataFn();
}
const lineTopData = ref({});
async function getLineDataFn() {
if (lineTabIndex.value == 0) {
getTopConceptPeriod({
start_time: "2025-09-06",
end_time: "2025-09-13",
limit_num: 10,
}).then((res) => {
lineTopData.value = res;
});
} else if (lineTabIndex.value == 1) {
getTopIndustryPeriod({
start_time: "2025-09-06",
end_time: "2025-09-13",
limit_num: 10,
}).then((res) => {
lineTopData.value = res;
});
} else if (lineTabIndex.value == 2) {
getTopSourcePeriod({
start_time: "2025-09-06",
end_time: "2025-09-13",
limit_num: 10,
}).then((res) => {
lineTopData.value = res;
});
}
} }
function goSreach() { function goSreach() {
@ -290,6 +331,8 @@ onMounted(async () => {
if (!Session.get("token")) { if (!Session.get("token")) {
LoginShow.value = true; LoginShow.value = true;
} }
getLineDataFn();
}); });
</script> </script>