提交 d970f091 authored 作者: yanpeng's avatar yanpeng

Merge branch 'master' into yp-dev

<template>
<div class="timeline-map">
<!-- 地图容器 -->
<div ref="chartRef" style="width: 100%; height: 600px;"></div>
<!-- 控制栏 -->
<div class="controls" style="margin-top: 16px; text-align: center;">
<button @click="play" :disabled="isPlaying">播放</button>
<button @click="pause" :disabled="!isPlaying">暂停</button>
<span style="margin: 0 16px;">速度:</span>
<input type="range" min="0.5" max="3" step="0.5" v-model.number="speed" />
<span>{{ speed }}x</span>
<div ref="map" style="width: 1600px; height: 551px"></div>
<div
style="width: 1231px; height: 72px; margin-top: -55px; background: linear-gradient(to top, #DAEBFD, #ffffff);margin-left: 182px">
<div style="width: 1231px; height: 40px; display: flex;justify-content: space-between;">
<div style="display: flex;align-self: center;">
<div class="time-btn">
</div>
<div class="time-btn">
</div>
<div class="time-btn">
重置
</div>
</div>
<div style="display: flex;align-self: center;">
<div>
当前时间:
</div>
<input></input>
<div style="margin: 0 10px 0 40px;color: #04295A;"> 刻度</div>
<select name="firstSelect" id="firstSelect">
<option value="option1">周制</option>
</select>
<div style="margin: 0 10px 0 40px;color: #04295A;">速率</div>
<select name="secondSelect" id="secondSelect" style="margin-right: 20px;">
<option value="optionA">1X</option>
<option value="optionB">2X</option>
</select>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';
import { GeoComponent } from 'echarts/components';
import { ScatterChart } from 'echarts/charts';
import { TooltipComponent } from 'echarts/components';
<div ref=" timeLineChart" style="width: 1231px; height: 30px;background-color: #6091D6; "></div>
</div>
// 注册必要组件
echarts.use([CanvasRenderer, GeoComponent, ScatterChart, TooltipComponent]);
</template>
// 导入中国地图 GeoJSON
import chinaJson from '@/assets/json/China.json';
<script>
import * as echarts from "echarts";
import worldJson from "@/assets/json/world.json";
// 事件数据(模拟)
const events = [
{
date: '2024-09-23',
desc: '在北京会见科技企业代表',
avatar: 'https://via.placeholder.com/32?text=BJ',
lng: 116.4074,
lat: 39.9042 // 北京
},
{
date: '2024-09-24',
desc: '在上海考察集成电路产业',
avatar: 'https://via.placeholder.com/32?text=SH',
lng: 121.4737,
lat: 31.2304 // 上海
},
{
date: '2024-09-25',
desc: '在深圳调研人工智能发展',
avatar: 'https://via.placeholder.com/32?text=SZ',
lng: 114.0579,
lat: 22.5431 // 深圳
export default {
name: "MapAnimation",
mounted() {
this.initMap();
},
{
date: '2024-09-26',
desc: '在成都出席科技创新论坛',
avatar: 'https://via.placeholder.com/32?text=CD',
lng: 104.0665,
lat: 30.5728 // 成都
}
];
// 响应式状态
const chartRef = ref(null);
const currentIndex = ref(0);
const isPlaying = ref(false);
const speed = ref(1);
let intervalId = null;
let myChart = null;
// 初始化图表
onMounted(() => {
// 注册中国地图(关键!)
echarts.registerMap('China', chinaJson);
myChart = echarts.init(chartRef.value);
const option = getOption();
myChart.setOption(option);
});
onUnmounted(() => {
if (intervalId) clearInterval(intervalId);
if (myChart) myChart.dispose();
});
// 获取 ECharts 配置
function getOption() {
return {
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(255,255,255,0.9)',
borderColor: '#ccc',
borderRadius: 6,
textStyle: { color: '#333', fontSize: 12 },
formatter(params) {
const data = params.data;
return `
<div style="padding:8px; line-height:1.4;">
<img src="${data.avatar}" width="24" height="24" style="border-radius:50%; vertical-align:middle; margin-right:6px;" />
<strong>${data.date}</strong><br/>
${data.desc}
</div>
`;
}
},
geo: {
map: 'China', // 使用注册的地图名
roam: true,
zoom: 1.2,
center: [105, 35], // 中国大致中心
label: {
show: false
},
itemStyle: {
areaColor: '#f0f9ff',
borderColor: '#a0cfff'
},
emphasis: {
itemStyle: {
areaColor: '#e6f7ff'
}
}
},
series: [
{
type: 'scatter',
coordinateSystem: 'geo',
data: getCurrentData(),
symbolSize: 12,
itemStyle: {
color: '#1890ff'
methods: {
initMap() {
// 注册自定义地图数据
echarts.registerMap("China", worldJson);
const chart = echarts.init(this.$refs.map);
const option = {
// timeline: {
// autoplay: true,
// playInterval: 2000,
// data: ["9月23日"]
// },
grid: {
left: "10%",
right: "10%",
bottom: "10%",
top: "10%",
containLabel: true
},
geo: {
map: "China",
roam: true,
label: {
emphasis: {
show: false,
color: "#fff"
}
},
silent: true,
itemStyle: {
areaColor: "#F6FAFF",
borderColor: "#B9DCFF"
}
},
label: {
series: [
{
name: "行程",
type: "effectScatter",
coordinateSystem: "geo",
data: [
{
time: "2025-02-01",
text: "随美国总统特朗普进行国事访问",
value: [116.46, 39.92],
itemStyle: { color: "#ffcc00" }
},
{
time: "2025-02-01",
text: "出席中国发展高层论坛2025年年会",
value: [116.46, 39.92],
itemStyle: { color: "#ffcc00" }
},
{
time: "2025-02-01",
text: "与民主党领导人查克·舒默及哈基姆...",
value: [1.46, 39.92],
itemStyle: { color: "#ffcc00" }
},
{
time: "2025-02-01",
text: "与阿拉伯国家领导人会晤,商讨加...",
value: [116.46, -44.92],
itemStyle: { color: "#ffcc00" }
},
{
time: "2025-02-01",
text: "对印度进行为期四天的访问,与总理...",
value: [78.1, 20.7],
itemStyle: { color: "#ffcc00" }
}
],
symbolSize: 10,
showEffectOn: "render",
rippleEffect: {
brushType: "stroke"
},
label: {
show: true,
position: "right",
offset: [5, 0],
borderColor: "rgba(174, 214, 255, 1)",
backgroundColor: "rgba(255, 255, 255, 0.8)",
formatter: params => {
const { time, text } = params.data; // 👈 从 params.data 取
return `{time|${time}} \n {text|${text}项}`;
},
rich: {
time: {
fontSize: 16,
fontFamily: "Microsoft YaHei",
fontWeight: 700,
lineHeight: 30,
color: "rgba(5, 95, 194, 1)"
},
text: {
fontSize: 14,
fontFamily: "Microsoft YaHei",
fontWeight: 400,
lineHeight: 22,
color: "rgb(95, 101, 108)"
}
}
},
itemStyle: {
color: "#ddb926",
shadowBlur: 10,
shadowColor: "#333"
}
}
]
};
chart.setOption(option);
const chart2 = echarts.init(this.$refs.timeLineChart);
const option2 = {
xAxis: {
type: "time",
position: "top",
axisLine: {
show: true,
lineStyle: {
color: "#000"
}
},
axisTick: {
show: false
},
axisLabel: {
formatter: "{value}日",
color: "#000"
},
splitLine: {
show: true
},
data: [
"2024-03-25",
"2024-04-08",
"2024-04-15",
"2024-04-22",
"2024-04-29",
"2024-05-06",
"2024-05-13",
"2024-05-20",
"2024-05-27",
"2024-06-03",
"2024-06-10",
"2024-06-17",
"2024-06-24",
"2024-07-01",
"2024-07-08",
"2024-07-15",
"2024-07-22",
"2024-07-29"
]
},
yAxis: {
type: "value",
show: false
},
series: [
{
data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
type: "line",
areaStyle: {},
emphasis: {
focus: "series"
}
}
],
visualMap: {
show: false,
dimension: 1,
pieces: [{ gt: 0, lte: 1, color: "#ffcc00" }]
}
}
]
};
}
// 获取当前要显示的数据
function getCurrentData() {
return [events[currentIndex.value]];
}
};
// 播放
function play() {
if (isPlaying.value) return;
isPlaying.value = true;
intervalId = setInterval(() => {
currentIndex.value = (currentIndex.value + 1) % events.length;
myChart.setOption({
series: [{ data: getCurrentData() }]
});
}, 1000 / speed.value);
}
// 暂停
function pause() {
if (!isPlaying.value) return;
isPlaying.value = false;
clearInterval(intervalId);
intervalId = null;
}
// 监听速度变化
watch(speed, () => {
if (isPlaying.value) {
pause();
play();
chart2.setOption(option2);
}
}
});
};
</script>
<style scoped>
.controls button {
margin: 0 8px;
padding: 6px 12px;
font-size: 14px;
#map {
width: 1600px;
height: 581px;
}
.time-btn {
color: #04295A;
background-color: #F9FDFE;
border: 1px solid #04295A;
padding: 0 10px;
margin: 0 10px;
}
</style>
\ No newline at end of file
</style>
......@@ -132,17 +132,16 @@
</div>
<!-- <div class="box3-header-title">{{ "人物动向" }}</div> -->
<div class="header-title"
style="width: 1560px;display: flex;justify-content: space-between;margin-top: 10px;">
style="width: 1560px; display: flex; justify-content: space-between; margin-top: 10px">
<div class="box3-header-title">
{{ "人物动向" }}
</div>
<div style="display: flex;gap: 8px;margin-right: 12px;">
<div style="display: flex; gap: 8px; margin-right: 12px">
<div v-for="value in peoDateList"
:class="peoDate !== value ? 'btn-box-samll' : 'btn-box-select-samll'">
{{ value }}
</div>
</div>
</div>
</div>
</div>
......@@ -156,17 +155,16 @@
<img src="./assets/images/header-message.png" alt="" />
</div>
<div class="header-title"
style="width: 1595px;display: flex;justify-content: space-between;margin-top: 10px;">
style="width: 1595px; display: flex; justify-content: space-between; margin-top: 10px">
<div>
{{ "重要人物言论及立场" }}
</div>
<div style="display: flex;gap: 8px;margin-right: 12px;">
<div style="display: flex; gap: 8px; margin-right: 12px">
<div v-for="value in fields"
:class="fieldSelect !== value ? 'btn-box-samll' : 'btn-box-select-samll'">
{{ value }}
</div>
</div>
</div>
</div>
<div class="box4-main">
......@@ -179,35 +177,43 @@
<div class="box5">
<div class="box5-header">
<div class="box5-header-left">
<div class="box5-header-icon" style="display: flex ">
<img src="./assets/images/box3-header-icon.png" alt="" style="/* 云端,云,云服务 1 */
width: 22px;
height: 22px;" />
<div class="box5-header-icon">
<img src="./assets/images/box3-header-icon.png" alt=""
style="margin: 13px 21px 13px 21px; height: 22px" />
<div class="box5-header-title">{{ "科技人物观点词云" }}</div>
</div>
<div>
<div style="display: flex">
<el-select v-model="wordCloudvalue" class="select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
<div style="height: 45px; display: flex; align-items: center">
<el-select v-model="wordCloudvalue" style="width: 120px; height: 28px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-select v-model="wordCloudfield" class="select">
<el-select v-model="wordCloudfield" style="width: 120px; height: 28px; margin: 10px 24px 10px 5px">
<el-option v-for="item in fieldSelect" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</div>
</div>
</div>
</div>
<div class="box5-main" id="box5Chart"></div>
</div>
<div class="box6">
<div class="box6-header">
<div class="box6-header" style="width: 790px">
<div class="header-icon">
<img src="./assets/images/box6-header-icon.png" alt="" />
</div>
<div class="header-title">{{ "科技人物观点涉及领域变化趋势" }}</div>
<div class="header-title"
style="display: flex; width: 740px; justify-content: space-between; align-items: center">
<div>
{{ "科技人物观点涉及领域变化趋势" }}
</div>
<el-select v-model="areaSelect" style="width: 120px; height: 28px">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
<div class="box6-main" id="box6Chart"></div>
</div>
......@@ -230,7 +236,19 @@ height: 22px;" />
<div class="box8-header-icon">
<img src="./assets/images/box6-header-icon.png" alt="" />
</div>
<div class="box8-header-title">{{ "主要人物涉华观点统计" }}</div>
<div style="display: flex; width: 730px; justify-content: space-between; align-items: center">
<div class="box8-header-title">{{ "主要人物涉华观点统计" }}</div>
<div style="gap: 8px;display: flex;">
<div v-for="value in viewOption"
:class="viewSelect !== value ? 'btn-box-samll' : 'btn-box-select-samll'">
{{ value }}
</div>
<el-select v-model="wordCloudvalue" style="width: 120px; height: 28px; margin-top: -5px;">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
</div>
</div>
<div class="box8-main">
......@@ -268,14 +286,14 @@ import setChart from "@/utils/setChart";
// 图表工具函数(仅保留用到的)
import getWordCloudChart from "./utils/worldCloudChart";
import getMultiLineChart from "./utils/multiLineChart";
import getDonutChart from './utils/donutChart.js';
import getDonutChart from "./utils/donutChart.js";
// 组件
import TimelineMap from "./component/TimelineMap.vue";
import PersonNewsCard from './component/PersonNewsCard.vue';
import PersonNewsCard from "./component/PersonNewsCard.vue";
import SpeechStance from "./component/speechStance.vue";
import PersonTable from './component/PersonTable.vue';
import SourceLibrary from './component/SourceLibrary.vue';
import PersonTable from "./component/PersonTable.vue";
import SourceLibrary from "./component/SourceLibrary.vue";
const router = useRouter();
......@@ -288,7 +306,7 @@ const handleBackHome = () => {
};
// 查看详情
const handleClickToDetail = (id) => {
const handleClickToDetail = id => {
const route = router.resolve({
path: "/marketAccessLayout",
query: { id }
......@@ -306,22 +324,29 @@ const warningList = ref([
]);
//人物动向
const peoDate = ref('今天')
const peoDateList = [
"今天",
"昨天",
"近三天",
"本周",
"本月"
]
const peoDate = ref("今天");
const peoDateList = ["今天", "昨天", "近三天", "本周", "本月"];
//重要人物言论及立场选择按钮
const fieldSelect = ref('全部领域')
const fields = ["全部领域", "集成电路", "能源", "生物科技", "量子科技", "人工智能", "通信网络", "航空航天", "海洋", "新材料", "先进制造"];
const fieldSelect = ref("全部领域");
const fields = [
"全部领域",
"集成电路",
"能源",
"生物科技",
"量子科技",
"人工智能",
"通信网络",
"航空航天",
"海洋",
"新材料",
"先进制造"
];
const yearList = ref(["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"]);
// 资源库分类
const categoryList = ref(["全部人物", "国会议员", "行政主官", "科技领袖", "顶尖科学家"]);
const activeCate = ref("全部人物");
const handleClickCate = (cate) => {
const handleClickCate = cate => {
activeCate.value = cate;
};
......@@ -335,30 +360,31 @@ const handleToMoreRiskSignal = () => {
// 词云数据
const wordCloudData = ref([
{ "name": "人工智能 (AI)", "value": 100 },
{ "name": "进行可再生能源税收减免", "value": 85 },
{ "name": "减少燃料对外依赖", "value": 80 },
{ "name": "评估中美现代化技术", "value": 75 },
{ "name": "应对中国制造2025战略", "value": 70 },
{ "name": "加强供应链风险管理", "value": 68 },
{ "name": "补贴和税收抵免", "value": 65 },
{ "name": "评估中美能源技术", "value": 60 },
{ "name": "实施能源税收延期", "value": 58 },
{ "name": "投资基础设施", "value": 55 },
{ "name": "禁止资助中国能源项目", "value": 53 },
{ "name": "限制采购中国产电池", "value": 50 },
{ "name": "加强美国在核能领域得到领导力", "value": 48 },
{ "name": "技术出口限制", "value": 45 },
{ "name": "出口管制与投资审查", "value": 42 },
{ "name": "供应链调整", "value": 40 },
{ "name": "左岸外包", "value": 38 },
{ "name": "空域主权与安全", "value": 36 },
{ "name": "抵制外国人才争夺", "value": 34 },
{ "name": "无人机先进空中交通", "value": 32 },
{ "name": "能源与基础设施", "value": 30 }
{ name: "人工智能 (AI)", value: 100 },
{ name: "进行可再生能源税收减免", value: 85 },
{ name: "减少燃料对外依赖", value: 80 },
{ name: "评估中美现代化技术", value: 75 },
{ name: "应对中国制造2025战略", value: 70 },
{ name: "加强供应链风险管理", value: 68 },
{ name: "补贴和税收抵免", value: 65 },
{ name: "评估中美能源技术", value: 60 },
{ name: "实施能源税收延期", value: 58 },
{ name: "投资基础设施", value: 55 },
{ name: "禁止资助中国能源项目", value: 53 },
{ name: "限制采购中国产电池", value: 50 },
{ name: "加强美国在核能领域得到领导力", value: 48 },
{ name: "技术出口限制", value: 45 },
{ name: "出口管制与投资审查", value: 42 },
{ name: "供应链调整", value: 40 },
{ name: "左岸外包", value: 38 },
{ name: "空域主权与安全", value: 36 },
{ name: "抵制外国人才争夺", value: 34 },
{ name: "无人机先进空中交通", value: 32 },
{ name: "能源与基础设施", value: 30 }
]);
const wordCloudfield = ref('全部领域')
const wordCloudvalue = ref("近十年");
const wordCloudfield = ref("全部领域");
const wordCloudvalue = ref("2025");
const areaSelect = ref("近十年");
const options = [
{
value: "近十年",
......@@ -382,9 +408,11 @@ const box6Chart = ref({
]
});
const viewOption = ref(["行政主管", "国会议员", "科技领袖", "顶尖科学家"]);
const viewSelect = ref("行政主管");
// 科技人物类型
const chart7Data = ref({
name: ['国会议员', '行政主官', '科技领袖', '顶尖科学家', '其他'],
name: ["国会议员", "行政主官", "科技领袖", "顶尖科学家", "其他"],
value: [482, 41, 83, 201, 25]
});
......@@ -394,10 +422,7 @@ onMounted(() => {
setChart(wordCloudChart, "box5Chart");
// 领域趋势
const chart6 = getMultiLineChart(
box6Chart.value.title,
...box6Chart.value.data.map(d => d.value)
);
const chart6 = getMultiLineChart(box6Chart.value.title, ...box6Chart.value.data.map(d => d.value));
setChart(chart6, "box6Chart");
// 人物类型
......@@ -906,7 +931,7 @@ onMounted(() => {
}
.box3-main {
height: 402px;
height: 590px;
overflow-y: auto;
overflow-x: hidden;
padding-top: 6px;
......@@ -980,19 +1005,22 @@ onMounted(() => {
background: rgba(255, 255, 255, 1);
.box5-header {
height: 53px;
width: 792px;
height: 48px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
margin: 0 auto;
display: flex;
justify-content: space-between;
padding: 0 20px;
position: relative;
.box5-header-left {
display: flex;
width: 792px;
justify-content: space-between;
.box5-header-icon {
padding: 13px 21px 13px 21px;
display: flex;
}
.box5-header-title {
......@@ -1142,7 +1170,7 @@ onMounted(() => {
display: flex;
.box8-header-icon {
margin-top: 15px;
margin-top: 18px;
margin-left: 2px;
width: 19px;
height: 19px;
......@@ -1154,8 +1182,7 @@ onMounted(() => {
}
.box8-header-title {
margin-top: 12px;
margin-left: 19px;
margin-left: 20px;
height: 26px;
color: rgba(20, 89, 187, 1);
font-family: Microsoft YaHei;
......@@ -1249,8 +1276,17 @@ onMounted(() => {
box-shadow: none !important;
}
.btn-box-samll {
:deep(.el-select__placeholder) {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
}
.btn-box-samll {
height: 28px;
/* 自动布局 */
display: flex;
......@@ -1265,12 +1301,11 @@ onMounted(() => {
border-radius: 4px;
background: rgba(255, 255, 255, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-size: 14px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
}
.btn-box-select-samll {
......@@ -1294,4 +1329,4 @@ onMounted(() => {
letter-spacing: 0px;
text-align: left;
}
</style>
\ No newline at end of file
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论