提交 d3f0ef39 authored 作者: Vicky's avatar Vicky

科技人物观点数据接入

上级 f9bbc15d
......@@ -27,6 +27,7 @@ export function getMainCharactersView(params) {
/**
* @param {year}
* @header token
* @areaId
*/
export function getCharacterOpinionWordCloud(params) {
return request({
......@@ -57,7 +58,7 @@ export function getOptionAreaChange(params) {
export function getPersonRelation(params) {
return request({
method: 'GET',
url: `/api/personRemarksOverview/personRelation/${params.industryId}`,
url: `/api/personRemarksOverview/personRelation`,
params,
})
}
......@@ -107,3 +108,29 @@ export function getBillRiskSignal(params) {
url: `/api/commonFeature/riskSignal/${params.moduleId}`,
})
}
//获取人物类别
export function getPersonType(params) {
return request({
method: 'GET',
url: `/api/commonDict/personType`,
params
})
}
// 获取人物全局信息 通过personId 获取personType
export function getPersonSummaryInfo(params) {
return request({
method: 'GET',
url: `/api/personHomepage/summaryInfo/${params.personId}`,
})
}
// 获取人物全局信息 通过personId 获取personType
export function getareaType(params) {
return request({
method: 'GET',
url: `/api/commonDict/areaType`,
params
})
}
\ No newline at end of file
<!-- PersonNewsCard.vue -->
<template>
<div class="person-news-card">
<el-carousel
ref="carouselRef"
height="354px"
:autoplay="true"
:interval="3000"
arrow="never"
indicator-position="none"
@change="handleCarouselChange"
>
<!-- <el-carousel-item v-for="(bill, billIndex) in hotBillList" :key="billIndex"> -->
<!-- 左侧:头像 -->
<div class="avatar">
<img :src="person.image_url" alt="人物头像" />
</div>
<!-- 事件列表 -->
......@@ -67,6 +79,8 @@
</div>
</div> -->
</div>
<!-- </el-carousel-item> -->
</el-carousel>
</div>
</template>
......@@ -74,6 +88,9 @@
// 导入数据
import data from "../json/personUpdates"; // 假设你把 JSON 存在 data.json 文件中
export default {
name: "PersonNewsCard",
data() {
......
......@@ -12,7 +12,7 @@
<div class="table-row" v-for="(item, index) in personList" :key="index">
<!-- 人物信息列 -->
<div class="row-col col-person">
<div style="margin: 7px 12px 7px 24px">
<div style="margin: 7px 12px 7px 24px;">
<img :src="item.avatar" class="avatar" alt="avatar" />
<div class="person-tags">
<div class="person-tag-bg" v-for="(tag, tIdx) in item.tags" :key="tIdx">
......@@ -46,10 +46,59 @@
</template>
<script setup>
import { ref } from "vue";
import { ref,onMounted,defineProps,watch } from "vue";
import personData from "../json/personData.json"; // 引入JSON数据
import {getMainCharactersView } from "@/api/technologyFigures/technologyFigures";
const props = defineProps({
persontypeid: {
type: String,
default: "004"
},
yearSelect:{
type: String,
default: "2025"
}
});
watch(() => [props.persontypeid,props.yearSelect], (val) => {
handlegetMainCharactersViewFn();
})
// 获取主要人物涉华观点统计
const handlegetMainCharactersViewFn = async () => {
const params = {
personTypeId: props.persontypeid,
year:props.yearSelect
};
try {
personList.value = [];
const res = await getMainCharactersView(params);
console.log("主要人物涉华观点统计", res);
if (res.code === 200) {
personList.value = res.data.map(item=>{
return{
avatar: item.personImage,
name: item.personName,
position: item.positionTitle,
tags: ["1", "2"],
chinaRelatedCount: item.remarksCount,
mediaQuoteCount: item.remarksCount
}
});
}
} catch (error) {}
};
onMounted(async () => {
handlegetMainCharactersViewFn();
});
const personList = ref(personData);
const personList = ref();
// 进度条状态
const getStatus = _percent => {
const percent = _percent;
......@@ -106,6 +155,9 @@ const getProgress = count => (count / getMaxCount()) * 100;
/* 表格内容样式 */
.table-body {
/* background-color: #fff; */
height: 300px;
overflow-y:scroll;
overflow-x:hidden;
}
.table-row {
......@@ -148,6 +200,7 @@ const getProgress = count => (count / getMaxCount()) * 100;
.person-info {
display: flex;
flex-direction: column;
}
.person-name {
......@@ -160,6 +213,11 @@ const getProgress = count => (count / getMaxCount()) * 100;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
width: 200px;
white-space:nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.person-position {
......
......@@ -2,37 +2,42 @@
<template>
<div class="source-library-container">
<div class="source-library-grid">
<div v-for="(item, index) in sourceLibraryData" :key="index" class="source-library-card">
<div v-for="(item, index) in PersonResource" :key="index" class="source-library-card" @click="handleClcikToCharacter(item.id)">
<div class="source-library-avatar-wrapper">
<img :src="item.avatar" alt="" class="source-library-avatar" />
</div>
<div class="source-library-text-content">
<div style="width: 240px">
<div style="width: 240px;height: 120px;display: flex; flex-direction: column;">
<h3 class="source-library-name">{{ item.name }}</h3>
<p class="source-library-title">{{ item.title }}</p>
<div class="taglist">
<p
class="source-library-tag"
:style="{
background: item.colorArray[2],
color: item.colorArray[0],
borderColor: item.colorArray[1]
v-for="value in item.tag"
:class="{tag1: value.typeId === '001',
tag2: value.typeId === '002',
tag3: value.typeId === '003',
tag4: value.typeId === '004',
tag5: value.typeId === '005',
tag6: value.typeId === '006',
}"
>
{{ item.tag }}
{{ value.typeName }}
</p>
</div>
</div>
</div>
</div>
</div>
<div class="page">
<div class="count">共1205项调查</div>
<div class="count">{{ `共${total}项调查`}}</div>
<el-pagination
v-model:current-page="currentPage"
@current-change="handleCurrentChange"
:page-size="pageSize"
:total="total"
layout="prev, pager, next"
:current-page="currentPage"
background
@current-change="handlePageChange"
layout="prev, pager, next"
:total="total"
/>
</div>
</div>
......@@ -41,10 +46,134 @@
<script setup>
// 导入数据(建议使用更具语义的变量名)
import sourceLibraryData from "../json/source.json";
import { ref } from "vue";
const total = ref(1205);
const pageSize = ref(121);
const currentPage = ref(5);
import { ref,onMounted } from "vue";
import { useRouter } from "vue-router";
import DefaultIcon1 from '@/assets/icons/default-icon1.png'
import DefaultIcon2 from '@/assets/icons/default-icon2.png'
import {getPersonResource,getPersonSummaryInfo } from "@/api/technologyFigures/technologyFigures";
const router = useRouter();
const total = ref(0);
const pageSize = ref(16);
const loading = ref(false);
const abortController = ref(null);
const currentPage = ref(1);
const PersonResource = ref([]);
// 获取人物资源库
const handlegetPersonResourceFn = async () => {
// 取消上一次未完成的请求
if (abortController.value) {
abortController.value.abort();
}
// 创建新的 AbortController
abortController.value = new AbortController();
loading.value = true;
const params = {
currentPage: currentPage.value - 1, // Standard Spring Boot page index is 0-based
pageSize: pageSize.value
};
try {
const res = await getPersonResource(params,abortController.value.signal);
console.log("人物资源库", res);
if (res.code === 200) {
if (res.data && res.data.content) {
PersonResource.value = res.data.content.map(item => ({
id: item.personId,
name: item.personName,
title: item.positionTitle,
tag: item.personTypeList,
avatar: item.personImage || DefaultIcon1
}));
total.value = res.data.totalElements;
} else {
PersonResource.value = [];
total.value = 0;
}
} else {
PersonResource.value = [];
total.value = 0;
}
loading.value = false;
} catch (error) {
if (error.name !== "AbortError") {
console.error(error);
loading.value = false;
}
}
};
// 处理页码改变事件
const handleCurrentChange = page => {
currentPage.value = page;
handlegetPersonResourceFn();
};
// 跳转人物主页
const handleClcikToCharacter = async (id) => {
const personTypeList = JSON.parse(window.sessionStorage.getItem("personTypeList"));
let type = 0;
let personTypeName = "";
const params = {
personId: id
};
try {
const res = await getPersonSummaryInfo(params);
console.log("人物全局信息", res);
if (res.code === 200 && res.data) {
const arr = personTypeList.filter(item => {
return item.typeId === res.data.personType;
});
console.log("arr", arr);
if (arr && arr.length > 0) {
personTypeName = arr[0].typeName;
console.log("personTypeName", personTypeName);
if (personTypeName === "科技企业领袖") {
type = 1;
} else if (personTypeName === "国会议员") {
type = 2;
} else if (personTypeName === "智库研究人员") {
type = 3;
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
return;
}
const route = router.resolve({
path: "/characterPage",
query: {
type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId: id
}
});
window.open(route.href, "_blank");
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} else {
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} catch (error) {}
};
onMounted(async () => {
handlegetPersonResourceFn();
});
const handlePageChange = p => {
currentPage.value = p;
};
......@@ -73,6 +202,8 @@ const handlePageChange = p => {
padding: 20px 18px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
cursor: pointer;
}
.source-library-card:hover {
......@@ -116,6 +247,7 @@ const handlePageChange = p => {
.source-library-text-content {
width: 656px;
flex: 1;
}
.source-library-name {
......@@ -133,7 +265,7 @@ const handlePageChange = p => {
width: 240px;
height: 48px;
color: rgba(59, 65, 75, 1);
margin: 11px 0 14px 0;
margin: 11px 0 0px 0;
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
......@@ -142,6 +274,13 @@ const handlePageChange = p => {
text-align: left;
}
.taglist{
display: flex;
gap: 10px;
margin-top: auto;
margin-bottom: 0px;
}
.source-library-tag {
/* width: 72px; */
height: 22px;
......@@ -153,10 +292,7 @@ const handlePageChange = p => {
padding: 1px 8px 1px 8px;
box-sizing: border-box;
border: 1px solid rgba(255, 229, 143, 1);
border-radius: 4px;
background: rgba(255, 251, 230, 1);
color: rgba(22, 119, 255, 1);
margin: 0;
font-family: Microsoft YaHei;
font-size: 14px;
......@@ -166,6 +302,37 @@ const handlePageChange = p => {
text-align: left;
}
.tag1 {
border: 1px solid rgba(217, 247, 190, 1);
background: rgba(246, 255, 237, 1);
color: rgba(82, 196, 26, 1);
}
.tag2 {
border: 1px solid rgba(186, 224, 255, 1);
background: rgba(230, 244, 255, 1);
color: rgba(22, 119, 255, 1);
}
.tag3 {
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
color: rgba(19, 168, 168, 1);
}
.tag4 {
border: 1px solid rgba(211, 173, 247, 1);
background: rgba(249, 240, 255, 1);
color: rgba(114, 46, 209, 1);
}
.tag5 {
border: 1px solid rgba(255, 229, 143, 1);
background: rgba(255, 251, 230, 1);
color: rgba(250, 173, 20, 1);
}
.tag6 {
border: 1px solid rgba(255, 163, 158, 1);
background: rgba(255, 241, 240, 1);
color: rgba(245, 34, 45, 1);
}
.page {
/* width: 1221px; */
width: 1600px;
......
......@@ -38,54 +38,168 @@
<script>
import * as echarts from "echarts";
import worldJson from "@/assets/json/world.json";
import {getCharacterTrends} from "@/api/technologyFigures/technologyFigures"
import { ref,onMounted } from "vue";
// const props = defineProps({
// peoDate: {
// type: String,
// default:"jinri"
// }
// })
// 获取人物动向
const CharacterTrends = ref([]);
const time = ref("");
const date = ref("");
const handlegetCharacterTrendsFn = async () => {
const params = {
startTime: "2025-01-01" || date.value
};
try {
const res = await getCharacterTrends(params);
console.log("人物动向", res);
if (res.code === 200) {
CharacterTrends.value = res.data.map(item=>{
return{
time: item.newsDate,
text: item.newsContent.substring(0, 17),
lon: item.lon || (Math.random() * 360 - 180).toFixed(6), //没数据
lat: item.lat || (Math.random() * 180 - 90).toFixed(6), //没数据
avatar: item.imageUrl
};
});
}
} catch (error) {}
};
function getDateDaysAgo(days) {
// 获取当前日期
const currentDate = new Date();
// 计算指定月数之前的日期
const pastDate = new Date(currentDate);
pastDate.setDate(currentDate.getDate() - days); // 减去指定的天数
// 格式化日期为 "YYYY-MM-DD" 的形式
const year = pastDate.getFullYear();
const month = String(pastDate.getMonth() + 1).padStart(2, "0"); // 月份从0开始,需要加1
const day = String(pastDate.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
}
// onMounted(async () => {
// handlegetCharacterTrendsFn();
// })
export default {
name: "MapAnimation",
mounted() {
props: {
peoDate: {
type: String,
default:"本周"
}
},
watch: {
async peoDate(Val) {
time.value = Val;
const days = ref();
if(time.value === "本周"){
days.value = 7;
}else if(time.value === "今天"){
days.value = 0;
}else if(time.value === "昨天"){
days.value = 1;
}else if(time.value === "近三天"){
days.value = 3;
}else if(time.value === "本月"){
days.value = new Date().getDate()-1;
}
date.value = getDateDaysAgo(days.value);
await handlegetCharacterTrendsFn();
this.initMap();
}
},
setup(props) {
onMounted(async () => {
time.value = props.peoDate;
const days = ref();
if(time.value === "本周"){
days.value = 7;
}else if(time.value === "今天"){
days.value = 0;
}else if(time.value === "昨天"){
days.value = 1;
}else if(time.value === "近三天"){
days.value = 3;
}else if(time.value === "本月"){
days.value = new Date().getDate()-1;
}
date.value = getDateDaysAgo(days.value);
});
},
async mounted() {
await handlegetCharacterTrendsFn();
this.initMap();
},
methods: {
initMap() {
// 注册自定义地图数据
echarts.registerMap("China", worldJson);
const eventsData = [
{
time: "9月23日",
text: "随美国总统特朗普进行国事访问",
lon: 116.46,
lat: 39.92,
avatar: "/testData/united_states 1 copy.png"
},
{
time: "9月23日",
text: "出席中国发展高层论坛2025年年会",
lon: 116.46,
lat: 39.92,
avatar: "/testData/united_states 1 copy.png"
},
{
time: "9月23日",
text: "与民主党领导人查克·舒默及哈基姆...",
lon: 1.46,
lat: 39.92,
avatar: "/testData/united_states 1 copy.png"
},
{
time: "9月23日",
text: "与阿拉伯国家领导人会晤,商讨加...",
lon: 116.46,
lat: -44.92,
avatar: "/testData/united_states 1 copy.png"
},
{
time: "9月23日",
text: "对印度进行为期四天的访问,与总理...",
lon: 78.1,
lat: 20.7,
avatar: "/testData/united_states 1 copy.png"
}
];
// const eventsData = [
// {
// time: "9月23日",
// text: "随美国总统特朗普进行国事访问",
// lon: 116.46,
// lat: 39.92,
// avatar: "/testData/united_states 1 copy.png"
// },
// {
// time: "9月23日",
// text: "出席中国发展高层论坛2025年年会",
// lon: 116.46,
// lat: 39.92,
// avatar: "/testData/united_states 1 copy.png"
// },
// {
// time: "9月23日",
// text: "与民主党领导人查克·舒默及哈基姆...",
// lon: 1.46,
// lat: 39.92,
// avatar: "/testData/united_states 1 copy.png"
// },
// {
// time: "9月23日",
// text: "与阿拉伯国家领导人会晤,商讨加...",
// lon: 116.46,
// lat: -44.92,
// avatar: "/testData/united_states 1 copy.png"
// },
// {
// time: "9月23日",
// text: "对印度进行为期四天的访问,与总理...",
// lon: 78.1,
// lat: 20.7,
// avatar: "/testData/united_states 1 copy.png"
// }
// ];
const eventsData = CharacterTrends;
const chart = echarts.init(this.$refs.map);
const option = {
grid: {
left: "10%",
......@@ -114,7 +228,7 @@ export default {
name: "行程",
type: "effectScatter",
coordinateSystem: "geo",
data: eventsData.map(item => ({
data: eventsData.value.map(item => ({
value: [item.lon, item.lat],
time: item.time,
text: item.text,
......@@ -149,6 +263,7 @@ export default {
};
chart.setOption(option);
// 添加 graphic 元素并设置其位置
this.updateGraphics(chart, eventsData);
......@@ -224,7 +339,7 @@ export default {
chart2.setOption(option2);
},
updateGraphics(chart, eventsData) {
const graphics = eventsData.map((event, index) => {
const graphics = eventsData.value.map((event, index) => {
const position = chart.convertToPixel({ geoIndex: 0 }, [event.lon, event.lat]);
return {
type: 'group',
......@@ -267,7 +382,8 @@ export default {
fontSize: 16,
fontWeight: '400',
fill: 'rgba(59, 65, 75, 1)', // 文字颜色(ECharts 中用 fill,不是 color)
textAlign: 'left'
textAlign: 'left',
}
}
]
......
......@@ -2,18 +2,19 @@
<template>
<div class="speech-stance-container">
<div class="speech-stance-grid">
<div v-for="(item, index) in speechStance" :key="index" class="speech-stance-card">
<div v-for="(item, index) in PersonRelation" :key="index" class="speech-stance-card">
<div class="speech-stance-avatar-wrapper">
<img :src="item.avatar" alt="" class="speech-stance-avatar" />
<img :src="item.personImage" alt="" class="speech-stance-avatar" />
</div>
<div class="speech-stance-text-content">
<div style="display: flex; width: 683px;">
<h3 class="speech-stance-name">{{ item.name }}</h3>
<p class="speech-stance-title">{{ item.title }}</p>
<h3 class="speech-stance-name">{{ item.personName }}</h3>
<p class="speech-stance-title">{{ item.positionTitle }}</p>
</div>
<p class="speech-stance-content">{{ item.content }}</p>
<p class="speech-stance-content">{{ item.remarks }}</p>
</div>
</div>
</div>
</div>
......@@ -21,7 +22,53 @@
<script setup>
// 导入数据
import { onMounted, ref,defineProps,watch } from "vue";
import speechStance from '../json/speechStance.json';
import {getPersonRelation} from "@/api/technologyFigures/technologyFigures"
const props = defineProps({
fieldSelected: {
type: String,
default: "全部领域"
},
areaId: {
type: String,
default: 0
}
});
const aId = ref();
const params = ref({});
watch(() => props.fieldSelected, (val) => {
aId.value = props.areaId;
if(val !== "全部领域"){
params.value.industryId = aId.value;
}else{
params.value = {};
}
handlegetPersonRelationFn();
})
// 获取重要人物言论及立场
const PersonRelation = ref([]);
const handlegetPersonRelationFn = async () => {
try {
const res = await getPersonRelation(params.value);
console.log("重要人物言论及立场", res);
if (res.code === 200) {
PersonRelation.value = res.data;
}
} catch (error) {}
};
onMounted(async () => {
handlegetPersonRelationFn();
});
</script>
<style scoped>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论