提交 1c65be4e authored 作者: coderBryanFu's avatar coderBryanFu

update

上级 8f982b4d
...@@ -25,10 +25,11 @@ export function getDecreeRiskSignal() { ...@@ -25,10 +25,11 @@ export function getDecreeRiskSignal() {
} }
// 行政令发布频度 // 行政令发布频度
export function getDecreeYearOrder() { export function getDecreeYearOrder(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/administrativeOrderOverview/yearOrder`, url: `/api/administrativeOrderOverview/yearOrder/${params.year}`,
params
}) })
} }
......
import request from "@/api/request.js"; import request from "@/api/request.js";
// 今日要闻 // 今日要闻
export function getTodayNew() { export function getTodayNews() {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/news/latestNews`, url: `/api/news/latestNews`,
...@@ -28,7 +28,7 @@ export function getHotNews() { ...@@ -28,7 +28,7 @@ export function getHotNews() {
}) })
} }
// 今日要闻-带参 // 中美博弈专题-带参
/** /**
* @param {industryId} * @param {industryId}
*/ */
...@@ -39,3 +39,19 @@ export function getHotNewsByArea(params) { ...@@ -39,3 +39,19 @@ export function getHotNewsByArea(params) {
params params
}) })
} }
// 获取模块类别
export function getMoudleType() {
return request({
method: 'GET',
url: `/api/commonDict/moduleType`,
})
}
// 获取领域列表
export function getAreaList() {
return request({
method: 'GET',
url: `/api/commonDict/areaType`,
})
}
\ No newline at end of file
import request from "@/api/request.js";
// 基本统计信息
export function getCountInfo() {
return request({
method: 'GET',
url: `/api/riskSignal/getCountInfo`,
})
}
// 每日统计信息
export function getDailyCount() {
return request({
method: 'GET',
url: `/api/riskSignal/getDailyCount`,
})
}
// 按条件分页查询风险信号信息
export function getPageQuery(data) {
return request({
method: 'POST',
url: `/api/riskSignal/pageQuery`,
data: data
})
}
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
class="source-item" class="source-item"
v-for="(item, index) in message.source" v-for="(item, index) in message.source"
:key="index" :key="index"
v-html="item" v-html="renderMarkdown(item)"
></div> ></div>
</div> </div>
<div v-if="message.content" class="answer-title">正文内容</div> <div v-if="message.content" class="answer-title">正文内容</div>
...@@ -71,7 +71,8 @@ ...@@ -71,7 +71,8 @@
<!-- 用户消息 --> <!-- 用户消息 -->
<div v-else class="user-item"> <div v-else class="user-item">
<div class="user-bubble"> <div class="user-bubble">
<div class="user-content">{{ message.content }}</div> <!-- <div class="user-content">{{ message.content }}</div> -->
<div class="user-content" v-html="renderMarkdown(message.content)"></div>
</div> </div>
</div> </div>
</div> </div>
...@@ -726,7 +727,7 @@ const sendMessage = async () => { ...@@ -726,7 +727,7 @@ const sendMessage = async () => {
} }
userInput.value = ""; userInput.value = "";
aiMessage.value = "" aiMessage.value = "";
if (curArea.value === "法案") { if (curArea.value === "法案") {
await connectSSE(question); await connectSSE(question);
} else { } else {
......
...@@ -242,9 +242,14 @@ ...@@ -242,9 +242,14 @@
</div> </div>
</div> </div>
<div class="box3-main"> <div class="box3-main">
<div class="box3-item" v-for="(news, index) in newsList" :key="index" @click="handleToNewsAnalysis(news)"> <div
class="box3-item"
v-for="(news, index) in newsList"
:key="index"
@click="handleToNewsAnalysis(news)"
>
<div class="left"> <div class="left">
<img :src="news.img" alt="" /> <img :src="news.img ? news.img : DefaultIconNews" alt="" />
</div> </div>
<div class="right"> <div class="right">
<div class="right-top"> <div class="right-top">
...@@ -266,7 +271,7 @@ ...@@ -266,7 +271,7 @@
<div class="box4-main"> <div class="box4-main">
<div class="box4-main-item" v-for="(item, index) in messageList" :key="index"> <div class="box4-main-item" v-for="(item, index) in messageList" :key="index">
<div class="left" @click="handleClickPerson()"> <div class="left" @click="handleClickPerson()">
<img :src="item.img" alt="" /> <img :src="item.img ? item.img : DefaultIcon1" alt="" />
</div> </div>
<div class="right"> <div class="right">
<div class="right-top"> <div class="right-top">
...@@ -290,7 +295,25 @@ ...@@ -290,7 +295,25 @@
<div class="box5-header-title">{{ "行政令发布频度" }}</div> <div class="box5-header-title">{{ "行政令发布频度" }}</div>
</div> </div>
</div> </div>
<div class="box5-main" id="chart1"></div>
<div class="box5-main">
<div class="box5-chart" id="chart1"></div>
<div class="box5-selectbox">
<el-select
@change="handleBox5YearChange"
v-model="box5SelectedYear"
placeholder="选择时间"
style="width: 80px"
>
<el-option
v-for="item in box5YearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</div> </div>
<div class="box6"> <div class="box6">
<div class="box6-header"> <div class="box6-header">
...@@ -341,17 +364,6 @@ ...@@ -341,17 +364,6 @@
<div class="home-main-footer"> <div class="home-main-footer">
<DivideHeader id="position4" class="divide4" :titleText="'资源库'"></DivideHeader> <DivideHeader id="position4" class="divide4" :titleText="'资源库'"></DivideHeader>
<div class="home-main-footer-header"> <div class="home-main-footer-header">
<div class="btn-box">
<div
class="btn"
:class="{ btnActive: activeCate === cate.id }"
v-for="(cate, index) in categoryList"
:key="index"
@click="handleClickCate(cate)"
>
{{ cate.name }}
</div>
</div>
<div class="select-box"> <div class="select-box">
<div class="paixu-btn" @click="handleSwithSort"> <div class="paixu-btn" @click="handleSwithSort">
<div class="icon1"> <div class="icon1">
...@@ -368,6 +380,27 @@ ...@@ -368,6 +380,27 @@
</div> </div>
<div class="home-main-footer-main"> <div class="home-main-footer-main">
<div class="left"> <div class="left">
<div class="select-box">
<div class="select-box-header">
<div class="icon"></div>
<div class="title">{{ "发布机构" }}</div>
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox
v-for="cate in govInsList"
:key="cate.id"
v-model="checkedGovIns"
:label="cate.name"
style="width: 180px"
class="filter-checkbox"
@change="handleChangeCheckedGovIns"
>
{{ cate.name }}
</el-checkbox>
</div>
</div>
</div>
<div class="select-box"> <div class="select-box">
<div class="select-box-header"> <div class="select-box-header">
<div class="icon"></div> <div class="icon"></div>
...@@ -505,6 +538,7 @@ import setChart from "@/utils/setChart"; ...@@ -505,6 +538,7 @@ import setChart from "@/utils/setChart";
import DefaultIcon1 from "@/assets/icons/default-icon1.png"; import DefaultIcon1 from "@/assets/icons/default-icon1.png";
import DefaultIcon2 from "@/assets/icons/default-icon2.png"; import DefaultIcon2 from "@/assets/icons/default-icon2.png";
import DefaultIconNews from "@/assets/icons/default-icon-news.png";
import p1 from "./assets/images/iconp1.png"; import p1 from "./assets/images/iconp1.png";
import p2 from "./assets/images/iconp2.png"; import p2 from "./assets/images/iconp2.png";
...@@ -575,39 +609,15 @@ const govInsList = ref([ ...@@ -575,39 +609,15 @@ const govInsList = ref([
// img: Gov2, // img: Gov2,
// name: "美国财政部" // name: "美国财政部"
// }, // },
// {
// img: Gov3,
// name: "美国能源部"
// },
// {
// img: Gov4,
// name: "美国商务部"
// },
// {
// img: Gov5,
// name: "美国战争部"
// },
// {
// img: Gov6,
// name: "联邦通信委员会 "
// },
// {
// img: Gov7,
// name: "食品药品监督管理局 (FDA)"
// },
// {
// img: Gov8,
// name: "美国航空航天局 (NASA)"
// },
// {
// img: Gov9,
// name: "美国国家卫生基金会 (NSF)"
// },
// {
// img: Gov10,
// name: "美国国立卫生研究院 (NIH)"
// }
]); ]);
const checkedGovIns = ref(['白宫'])
const handleChangeCheckedGovIns = (val) => {
}
const handleGetDepartmentList = async () => { const handleGetDepartmentList = async () => {
try { try {
const res = await getDepartmentList(); const res = await getDepartmentList();
...@@ -782,15 +792,13 @@ const handleGetNews = async () => { ...@@ -782,15 +792,13 @@ const handleGetNews = async () => {
}; };
handleGetNews(); handleGetNews();
// 点击新闻条目,跳转到新闻分析页 // 点击新闻条目,跳转到新闻分析页
const handleToNewsAnalysis = (news) => { const handleToNewsAnalysis = news => {
const route = router.resolve( const route = router.resolve({
{
path: "/newsAnalysis", path: "/newsAnalysis",
query: { query: {
newsId: news.newsId newsId: news.newsId
} }
} });
);
window.open(route.href, "_blank"); window.open(route.href, "_blank");
}; };
...@@ -844,27 +852,54 @@ const chart1Data = ref({ ...@@ -844,27 +852,54 @@ const chart1Data = ref({
dataY: [] dataY: []
}); });
const box5YearList = ref([
{
label: "2025",
value: "2025"
},
{
label: "2024",
value: "2024"
},
{
label: "2023",
value: "2023"
},
{
label: "2022",
value: "2022"
},
{
label: "2021",
value: "2021"
}
]);
const box5SelectedYear = ref("2025");
const handleGetDecreeYearOrder = async () => { const handleGetDecreeYearOrder = async () => {
const params = {
year: box5SelectedYear.value
};
try { try {
const res = await getDecreeYearOrder(); const res = await getDecreeYearOrder(params);
console.log("行政令发布频度", res); console.log("行政令发布频度", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
chart1Data.value.dataX = res.data chart1Data.value.dataX = res.data.map(item => {
.map(item => {
return item.year; return item.year;
}) });
.reverse(); chart1Data.value.dataY = res.data.map(item => {
chart1Data.value.dataY = res.data
.map(item => {
return item.count; return item.count;
}) });
.reverse();
} }
} catch (error) { } catch (error) {
console.error("行政令发布频度error", error); console.error("行政令发布频度error", error);
} }
}; };
const handleBox5YearChange = val => {
handleBox5();
};
const handleBox5 = async () => { const handleBox5 = async () => {
await handleGetDecreeYearOrder(); await handleGetDecreeYearOrder();
let chart1 = getBarChart(chart1Data.value.dataX, chart1Data.value.dataY); let chart1 = getBarChart(chart1Data.value.dataX, chart1Data.value.dataY);
...@@ -977,19 +1012,6 @@ const handleSwithSort = () => { ...@@ -977,19 +1012,6 @@ const handleSwithSort = () => {
isSort.value = !isSort.value; isSort.value = !isSort.value;
}; };
const categoryList = computed(() => {
let obj = {
name: "全部分类",
id: "",
img: ""
};
return [obj, ...govInsList.value];
});
const activeCate = ref("白宫");
const handleClickCate = cate => {
activeCate.value = cate.id;
};
const handleToPosi = id => { const handleToPosi = id => {
// 0 618 1240 2350 // 0 618 1240 2350
...@@ -1066,12 +1088,13 @@ const decreeList = ref([ ...@@ -1066,12 +1088,13 @@ const decreeList = ref([
]); ]);
const handleGetDecreeOrderList = async () => { const handleGetDecreeOrderList = async () => {
const p0 = checkedGovIns.value.join(',')
const p1 = activeAreaList.value.join(","); const p1 = activeAreaList.value.join(",");
const p2 = activePubTime.value.join(","); const p2 = activePubTime.value.join(",");
const params = { const params = {
currentPage: 0, currentPage: 0,
pageSize: 999999, pageSize: 999999,
proposeName: activeCate.value, proposeName: p0,
researchTypeIds: p1, researchTypeIds: p1,
sortFun: isSort.value, sortFun: isSort.value,
years: p2 years: p2
...@@ -1123,18 +1146,19 @@ watch( ...@@ -1123,18 +1146,19 @@ watch(
); );
watch( watch(
() => activeCate.value, () => isSort.value,
val => { val => {
handleGetDecreeOrderList(); handleGetDecreeOrderList();
} }
); );
watch( watch(
() => isSort.value, () => checkedGovIns.value,
val => { val => {
handleGetDecreeOrderList(); handleGetDecreeOrderList();
} }
);
)
// 切换当前政令 // 切换当前政令
const handleSwithCurDecree = name => { const handleSwithCurDecree = name => {
...@@ -2545,6 +2569,15 @@ onMounted(async () => { ...@@ -2545,6 +2569,15 @@ onMounted(async () => {
} }
.box5-main { .box5-main {
height: 397px; height: 397px;
position: relative;
.box5-selectbox {
position: absolute;
right: 10px;
top: 10px;
}
.box5-chart {
height: 397px;
}
} }
} }
.box6 { .box6 {
...@@ -2755,10 +2788,10 @@ onMounted(async () => { ...@@ -2755,10 +2788,10 @@ onMounted(async () => {
} }
.home-main-footer-header { .home-main-footer-header {
width: 1600px; width: 1600px;
height: 70px; height: 50px;
margin: 36px auto 16px; margin: 0 auto 16px;
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
.btn-box { .btn-box {
margin-top: 10px; margin-top: 10px;
width: 1450px; width: 1450px;
...@@ -2853,7 +2886,7 @@ onMounted(async () => { ...@@ -2853,7 +2886,7 @@ onMounted(async () => {
gap: 16px; gap: 16px;
.left { .left {
width: 300px; width: 300px;
height: 666px; // height: 666px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
box-sizing: border-box; box-sizing: border-box;
...@@ -3045,7 +3078,7 @@ onMounted(async () => { ...@@ -3045,7 +3078,7 @@ onMounted(async () => {
.footer-box { .footer-box {
margin: 0 30px; margin: 0 30px;
height: 32px; height: 32px;
margin-top: 30px; margin-top: 20px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.footer-left { .footer-left {
......
...@@ -4,7 +4,7 @@ const getBarChart = (nameList, valueList) => { ...@@ -4,7 +4,7 @@ const getBarChart = (nameList, valueList) => {
const option = { const option = {
tooltip: {}, tooltip: {},
grid: { grid: {
top: '3%', top: '8%',
right: '3%', right: '3%',
bottom: '3%', bottom: '3%',
left: '3%', left: '3%',
......
...@@ -13,7 +13,7 @@ const getPieChart = (data) => { ...@@ -13,7 +13,7 @@ const getPieChart = (data) => {
}, },
label: { label: {
alignTo: 'edge', alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 条 {d}%}', formatter: '{name|{b}}\n{time|{d}%}',
minMargin: 5, minMargin: 5,
edgeDistance: 10, edgeDistance: 10,
lineHeight: 24, lineHeight: 24,
......
<template>
<div class="fishbone-wrapper">
<div class="fishbone-scroll-container" ref="scrollContainerRef">
<div class="fishbone" ref="fishboneRef" v-if="fishboneData.length > 0">
<div class="main-line" :style="{ width: (fishboneData.length / 2) * 340 - 200 + 'px' }"></div>
<!-- 奇数索引的数据组放在上方 -->
<div
v-for="(causeGroup, groupIndex) in getOddGroups(fishboneData)"
:key="'top-' + groupIndex"
:class="getTopBoneClass(groupIndex)"
:style="{ left: groupIndex * 300 + 400 + 'px' }"
>
<div class="left-bone">
<div
class="left-bone-item"
v-for="(item, index) in getLeftItems(causeGroup.causes)"
:key="'left-' + index"
>
<div class="text">{{ item.name }}</div>
<div class="line"></div>
</div>
</div>
<div class="right-bone">
<div
class="right-bone-item"
v-for="(item, index) in getRightItems(causeGroup.causes)"
:key="'right-' + index"
>
<div class="line"></div>
<div class="text">{{ item.name }}</div>
</div>
</div>
</div>
<!-- 偶数索引的数据组放在下方 -->
<div
v-for="(causeGroup, groupIndex) in getEvenGroups(fishboneData)"
:key="'bottom-' + groupIndex"
:class="getBottomBoneClass(groupIndex)"
:style="{ left: groupIndex * 300 + 200 + 'px' }"
>
<div class="left-bone">
<div
class="left-bone-item"
v-for="(item, index) in getLeftItems(causeGroup.causes)"
:key="'left-bottom-' + index"
>
<div class="text">{{ item.name }}</div>
<div class="line"></div>
</div>
</div>
<div class="right-bone">
<div
class="right-bone-item"
v-for="(item, index) in getRightItems(causeGroup.causes)"
:key="'right-bottom-' + index"
>
<div class="line"></div>
<div class="text">{{ item.name }}</div>
</div>
</div>
</div>
</div>
<div v-else style="display: flex; justify-content: center; align-items: center; height: 200px; width: 100%">
<el-empty description="暂无相关数据" />
</div>
</div>
<!-- 滚动指示器 -->
<!-- <div class="scroll-indicators" v-if="showScrollIndicator">
<div class="scroll-btn left" :class="{ disabled: !canScrollLeft }" @click="scrollLeft">‹</div>
<div class="scroll-btn right" :class="{ disabled: !canScrollRight }" @click="scrollRight">›</div>
</div> -->
</div>
</template>
<script setup>
import { getChainFishbone } from "@/api/exportControl";
import { onMounted, ref, nextTick, watch } from "vue";
// 这儿需要接收父组件传递来的产业链ID
const props = defineProps({
chainId: {
type: Number,
default: 1
}
});
// const chainId = ref(1);
const fishboneData = ref([]);
const scrollContainerRef = ref(null);
const fishboneRef = ref(null);
const showScrollIndicator = ref(false);
const canScrollLeft = ref(false);
const canScrollRight = ref(true);
// 获取奇数索引的数据组(放在上方)
const getOddGroups = data => {
console.log(
"getOddGroups:",
data.filter((_, index) => index % 2 === 1)
);
return data.filter((_, index) => index % 2 === 1);
};
// 获取偶数索引的数据组(放在下方)
const getEvenGroups = data => {
console.log(
"getEvenGroups:",
data.filter((_, index) => index % 2 === 0)
);
return data.filter((_, index) => index % 2 === 0);
};
// 获取上方鱼骨图位置类名
const getTopBoneClass = index => {
const positions = ["top-bone", "top-bone1", "top-bone2"];
return positions[index % 3] || "top-bone";
};
// 获取下方鱼骨图位置类名
const getBottomBoneClass = index => {
const positions = ["bottom-bone", "bottom-bone1", "bottom-bone2"];
return positions[index % 3] || "bottom-bone";
};
// 获取左侧显示的项目(前半部分)
const getLeftItems = items => {
const midpoint = Math.ceil(items.length / 2);
return items.slice(0, midpoint);
};
// 获取右侧显示的项目(后半部分)
const getRightItems = items => {
const midpoint = Math.ceil(items.length / 2);
return items.slice(midpoint);
};
// 检查滚动状态
const updateScrollState = () => {
if (!scrollContainerRef.value) return;
const container = scrollContainerRef.value;
canScrollLeft.value = container.scrollLeft > 0;
canScrollRight.value = container.scrollLeft < container.scrollWidth - container.clientWidth;
};
// 滚动处理
const scrollLeft = () => {
if (scrollContainerRef.value) {
scrollContainerRef.value.scrollBy({ left: -200, behavior: "smooth" });
}
};
const scrollRight = () => {
if (scrollContainerRef.value) {
scrollContainerRef.value.scrollBy({ left: 200, behavior: "smooth" });
}
};
// 处理滚动事件
const handleScroll = () => {
updateScrollState();
};
onMounted(async () => {
try {
const chainFishboneData = await getChainFishbone(props.chainId);
fishboneData.value = chainFishboneData?.causes ?? [];
// 等待DOM更新后检查是否需要滚动
nextTick(() => {
if (scrollContainerRef.value && fishboneRef.value) {
showScrollIndicator.value = fishboneRef.value.scrollWidth > scrollContainerRef.value.clientWidth;
updateScrollState();
}
});
console.log("鱼骨图数据:", fishboneData.value);
} catch (error) {
console.log(error);
}
});
// 监听props中的chainId变化
watch(
() => props.chainId,
async () => {
try {
const chainFishboneData = await getChainFishbone(props.chainId);
fishboneData.value = chainFishboneData?.causes ?? [];
} catch (error) {
console.log(error);
}
}
);
</script>
<style lang="scss" scoped>
.fishbone-wrapper {
position: relative;
width: 100%;
height: 100%;
}
.fishbone-scroll-container {
display: flex;
align-items: center;
width: 100%;
height: 100%;
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: thin;
scrollbar-color: rgba(144, 202, 249, 0.5) transparent;
&::-webkit-scrollbar {
height: 6px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background-color: rgba(144, 202, 249, 0.5);
border-radius: 3px;
}
}
/* ... 原有的样式保持不变 ... */
.fishbone {
position: relative;
width: fit-content;
height: 100%;
margin-top: 40px;
min-width: 100%;
padding-left: 275px;
.main-line {
margin-top: 280px;
width: 1888px;
height: 3px;
background: rgba(174, 208, 255, 1);
}
}
.top-bone {
position: absolute;
top: 20px;
right: 200px;
width: 3px;
height: 260px;
background: #90caf9;
transform: skew(30deg);
z-index: 1;
.left-bone {
color: #777;
position: absolute;
top: 0;
left: -150px;
width: 150px;
height: 260px;
.left-bone-item {
transform: skew(-30deg);
height: 35px;
margin-bottom: 5px;
margin-top: 15px;
display: flex;
justify-content: flex-end;
.text {
margin-left: 4px;
height: 70px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line {
margin-left: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
}
}
.right-bone {
color: #777;
position: absolute;
top: 0;
right: -150px;
width: 150px;
height: 260px;
.right-bone-item {
transform: skew(-30deg);
height: 35px;
margin-bottom: 15px;
margin-top: 5px;
display: flex;
justify-content: flex-start;
.line {
margin-right: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
.text {
width: 100px;
margin-right: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.top-bone1 {
position: absolute;
top: 20px;
right: 500px;
width: 3px;
height: 260px;
background: #90caf9;
transform: skew(30deg);
z-index: 1;
.left-bone {
color: #777;
position: absolute;
top: 0;
left: -150px;
width: 150px;
height: 260px;
.left-bone-item {
transform: skew(-30deg);
height: 35px;
margin-bottom: 5px;
margin-top: 15px;
display: flex;
justify-content: flex-end;
.text {
width: 100px;
margin-left: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line {
margin-left: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
}
}
.right-bone {
color: #777;
position: absolute;
top: 0;
right: -150px;
width: 150px;
height: 260px;
.right-bone-item {
transform: skew(-30deg);
height: 35px;
margin-bottom: 15px;
margin-top: 5px;
display: flex;
justify-content: flex-start;
.line {
margin-right: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
.text {
width: 100px;
margin-right: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.top-bone2 {
position: absolute;
top: 20px;
right: 800px;
width: 3px;
height: 260px;
background: #90caf9;
transform: skew(30deg);
z-index: 1;
.left-bone {
color: #777;
position: absolute;
top: 0;
left: -150px;
width: 150px;
height: 260px;
.left-bone-item {
transform: skew(-30deg);
height: 35px;
margin-bottom: 5px;
margin-top: 15px;
display: flex;
justify-content: flex-end;
.text {
width: 100px;
margin-left: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line {
margin-left: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
}
}
.right-bone {
color: #777;
position: absolute;
top: 0;
right: -150px;
width: 150px;
height: 260px;
.right-bone-item {
transform: skew(-30deg);
height: 35px;
margin-bottom: 15px;
margin-top: 5px;
display: flex;
justify-content: flex-start;
.line {
margin-right: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
.text {
width: 100px;
margin-right: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.bottom-bone {
position: absolute;
top: 280px;
right: 360px;
width: 3px;
height: 260px;
background: #90caf9;
transform: skew(-30deg);
z-index: 1;
.left-bone {
color: #777;
position: absolute;
top: 0;
left: -150px;
width: 150px;
height: 260px;
.left-bone-item {
transform: skew(30deg);
height: 35px;
margin-bottom: 5px;
margin-top: 15px;
display: flex;
justify-content: flex-end;
.text {
width: 100px;
margin-left: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line {
margin-left: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
}
}
.right-bone {
color: #777;
position: absolute;
top: 0;
right: -150px;
width: 150px;
height: 260px;
.right-bone-item {
transform: skew(30deg);
height: 35px;
margin-bottom: 15px;
margin-top: 5px;
display: flex;
justify-content: flex-start;
.line {
margin-right: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
.text {
width: 100px;
margin-right: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.bottom-bone1 {
position: absolute;
top: 280px;
right: 660px;
width: 3px;
height: 260px;
background: #90caf9;
transform: skew(-30deg);
z-index: 1;
.left-bone {
color: #777;
position: absolute;
top: 0;
left: -150px;
width: 150px;
height: 260px;
.left-bone-item {
transform: skew(30deg);
height: 35px;
margin-bottom: 5px;
margin-top: 15px;
display: flex;
justify-content: flex-end;
.text {
width: 100px;
margin-left: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line {
margin-left: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
}
}
.right-bone {
color: #777;
position: absolute;
top: 0;
right: -150px;
width: 150px;
height: 260px;
.right-bone-item {
transform: skew(30deg);
height: 35px;
margin-bottom: 15px;
margin-top: 5px;
display: flex;
justify-content: flex-start;
.line {
margin-right: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
.text {
width: 100px;
margin-right: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.bottom-bone2 {
position: absolute;
top: 280px;
right: 960px;
width: 3px;
height: 260px;
background: #90caf9;
transform: skew(-30deg);
z-index: 1;
.left-bone {
color: #777;
position: absolute;
top: 0;
left: -150px;
width: 150px;
height: 260px;
.left-bone-item {
transform: skew(30deg);
height: 35px;
margin-bottom: 5px;
margin-top: 15px;
display: flex;
justify-content: flex-end;
.text {
width: 100px;
margin-left: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.line {
margin-left: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
}
}
.right-bone {
color: #777;
position: absolute;
top: 0;
right: -150px;
width: 150px;
height: 260px;
.right-bone-item {
transform: skew(30deg);
height: 35px;
margin-bottom: 15px;
margin-top: 5px;
display: flex;
justify-content: flex-start;
.line {
margin-right: 7px;
margin-top: 16px;
width: 30px;
height: 2px;
background: rgba(174, 208, 255, 1);
}
.text {
width: 100px;
margin-right: 4px;
height: 35px;
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
.scroll-indicators {
position: absolute;
top: 50%;
left: 0;
right: 0;
transform: translateY(-50%);
display: flex;
justify-content: space-between;
pointer-events: none;
padding: 0 10px;
z-index: 10;
}
.scroll-btn {
width: 30px;
height: 30px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.8);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: bold;
color: #90caf9;
cursor: pointer;
pointer-events: auto;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
transition: all 0.2s ease;
&:hover:not(.disabled) {
background: #90caf9;
color: white;
transform: scale(1.1);
}
&.disabled {
color: #c0c4cc;
cursor: not-allowed;
background: rgba(255, 255, 255, 0.5);
}
}
</style>
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<div class="box1"> <div class="box1">
<div class="box-header"> <div class="box-header">
<div class="icon"></div> <div class="icon"></div>
<div class="title">{{ "企业影响分析" }}</div> <div class="title">{{ "涉及行业" }}</div>
<div class="header-right1"> <div class="header-right1">
<el-checkbox v-model="isCRelated" label="只看中国企业" size="large" /> <el-checkbox v-model="isCRelated" label="只看中国企业" size="large" />
</div> </div>
...@@ -59,9 +59,11 @@ ...@@ -59,9 +59,11 @@
<div class="box2"> <div class="box2">
<div class="box-header"> <div class="box-header">
<div class="icon"></div> <div class="icon"></div>
<div class="title">{{ "政令举措落实分析" }}</div> <div class="title">{{ "产业链分析" }}</div>
<div class="header-right1"></div>
<div class="header-right"> <div class="header-right">
<div class="header-right-icon">
<img src="@/assets/icons/box-header-icon1.png" alt="" />
</div>
<div class="header-right-icon"> <div class="header-right-icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" /> <img src="@/assets/icons/box-header-icon2.png" alt="" />
</div> </div>
...@@ -70,84 +72,51 @@ ...@@ -70,84 +72,51 @@
</div> </div>
</div> </div>
</div> </div>
<div class="box2-main"> <div class="box2-main">
<div class="box2-line-box" v-if="timeLineList.length"></div> <div class="box2-main-header">
<div <div class="box2-main-header-left">
class="box2-item"
:class="{ box2ItemFooter: index % 2 }"
v-for="(item, index) in timeLineList"
:key="index"
>
<div class="point" :class="{ pointFooter: index % 2 }">
<img src="./assets/images/point.png" alt="" />
</div>
<div class="box2-item-header">
<div class="title">{{ item.time }}</div>
</div>
<div class="box2-item-content">
{{ item.content }}
</div>
</div>
</div>
<div class="box2-footer">
<div class="footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" /> <img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div> </div>
<div class="footer-center"> <div class="box2-main-header-center">
{{ {{
`政令目前仍处于关键的执行框架搭建期。该政令旨在通过推动“全栈式”美国AI技术出口,巩固其技术霸权并减少国际社会对美国对手国家技术的依赖` "法案核心意图在于通过税收优惠吸引制造业回流美国​,并在关键科技领域对中国进行遏制,限制中国获取先进技术、资本和市场渠道,从而延缓中国科技产业的发展速度。给半导体、新能源、人工智能等相关科技行业带来不小的短期压力。"
}} }}
</div> </div>
<div class="footer-right"> <div class="box2-main-header-right">
<img src="@/assets/icons/box-footer-right-icon.png" alt="" /> <img src="@/assets/icons/box-footer-right-icon.png" alt="" />
</div> </div>
</div> </div>
<div class="box2-main-main">
<Fishbone :chainId="2" />
</div> </div>
<div class="box3"> <div class="box2-main-footer">
<div class="box-header"> <div class="box2-main-footer-left">
<div class="icon"></div> <div class="top">
<div class="title">{{ "历史相似举措及落实情况" }}</div> <div class="icon">
<div class="header-right1"></div> <img src="@/assets/icons/warning.png" alt="" />
<div class="header-right">
<div class="header-right-icon">
<img src="@/assets/icons/box-header-icon2.png" alt="" />
</div>
<div class="header-right-icon">
<img src="@/assets/icons/box-header-icon3.png" alt="" />
</div>
</div>
</div>
<div class="box3-main">
<div class="box3-item" v-for="(item, index) in box3List" :key="index">
<div class="box3-item-left">
<div class="text">
{{ item.type }}
</div> </div>
<div class="text">{{ "中国企业45家(51.00%),受制裁5家(7.00%)" }}</div>
</div> </div>
<div class="box3-item-right"> <div class="bottom">{{ "基础支撑" }}</div>
<div class="right-top">
<div class="title">{{ item.title }}</div>
<div class="tag">{{ item.tag }}</div>
</div> </div>
<div class="right-footer"> <div class="box2-main-footer-center">
<div class="content">{{ item.content }}</div> <div class="top">
<div class="time">{{ item.time }}</div> <div class="icon">
<img src="@/assets/icons/warning.png" alt="" />
</div> </div>
<div class="text">{{ "中国企业45家(51.00%),受制裁8家(7.00%)" }}</div>
</div> </div>
<div class="bottom">{{ "软件算法" }}</div>
</div> </div>
<div class="box2-main-footer-right">
<div class="top">
<div class="icon">
<img src="@/assets/icons/warning.png" alt="" />
</div> </div>
<div class="box3-footer"> <div class="text">{{ "中国企业45家(51.00%),受制裁8家(7.00%)" }}</div>
<div class="footer-left">
<img src="@/assets/icons/box-footer-left-icon.png" alt="" />
</div> </div>
<div class="footer-center"> <div class="bottom">{{ "行业应用" }}</div>
{{
`中美经济深度交织,全面脱钩成本高昂且不现实。其核心揭示了三大纽带:生产网络相互依存使强行分离代价巨大;人才双向流动推动创新却成政策博弈焦点;能源领域合作与竞争并存,关乎全球气候治理与经济博弈。报告主张理性竞合,在竞争中找到合作路径。`
}}
</div> </div>
<div class="footer-right">
<img src="@/assets/icons/box-footer-right-icon.png" alt="" />
</div> </div>
</div> </div>
</div> </div>
...@@ -157,6 +126,7 @@ ...@@ -157,6 +126,7 @@
<script setup> <script setup>
import { ref, computed, watch, onMounted } from "vue"; import { ref, computed, watch, onMounted } from "vue";
import Fishbone from "./fishbone.vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import router from "@/router"; import router from "@/router";
import setChart from "@/utils/setChart"; import setChart from "@/utils/setChart";
...@@ -569,291 +539,207 @@ onMounted(() => { ...@@ -569,291 +539,207 @@ onMounted(() => {
} }
} }
.right { .right {
margin-left: 17px;
margin-top: 16px; margin-top: 16px;
margin-left: 16px;
.box2 { .box2 {
width: 1103px; width: 1105px;
height: 415px; height: 847px;
background: rgba(255, 255, 255);
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box2-main {
margin: 0 auto;
margin-top: 10px;
height: 260px;
width: 1054px;
overflow-x: auto;
overflow-y: hidden;
display: flex;
position: relative; position: relative;
padding-left: 120px; .box2-main {
.box2-line-box { height: 799px;
position: absolute; .box2-main-header {
left: 0; margin: 14px auto 36px;
top: 114px; width: 1066px;
height: 8px;
width: 1054px;
background: url("./assets/images/line-bg.png") repeat;
}
.box2-item {
width: 300px;
height: 120px;
position: relative;
box-sizing: border-box;
padding-left: 13px;
margin-left: -100px;
border-left: 1px solid #0a57a6;
.box2-item-header {
display: flex;
width: 240px;
.title {
color: var(--color-main-active);
height: 26px;
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
}
}
.box2-item-content {
width: 210px;
min-height: 48px;
max-height: 96px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
overflow: hidden;
}
.point {
position: absolute;
left: -8px;
bottom: -7px;
width: 15px;
height: 15px;
img {
width: 100%;
height: 100%;
}
}
.pointFooter {
position: absolute;
left: -8px;
top: -7px;
width: 15px;
height: 15px;
img {
width: 100%;
height: 100%;
}
}
.time {
height: 24px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
line-height: 24px;
position: absolute;
bottom: -36px;
left: 0;
}
}
.box2ItemFooter {
margin-top: 118px;
margin-left: -120px;
box-sizing: border-box;
padding-top: 20px;
// display: flex;
// flex-direction: column;
// justify-content: flex-end;
}
}
.box2-footer {
margin-top: 6px;
width: 1057px;
height: 64px; height: 64px;
box-sizing: border-box; box-sizing: border-box;
border: 1px rgba(231, 243, 255, 1); border: 1px solid rgba(231, 243, 255, 1);
border-radius: 4px; border-radius: 4px;
background: rgba(246, 251, 255, 1); background: rgba(246, 250, 255, 1);
margin: 14px auto 0; padding: 6px 12px;
padding: 6px 12px 6px 12px;
display: flex; display: flex;
.footer-left { align-items: center;
justify-content: center;
gap: 13px;
.box2-main-header-left {
width: 19px; width: 19px;
height: 20px; height: 20px;
margin-top: 16px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
.footer-center { .box2-main-header-center {
margin-left: 13px; width: 973px;
width: 964px;
height: 48px; height: 48px;
color: var(--color-main-active); color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
display: flex; letter-spacing: 0px;
align-items: center; text-align: left;
} }
.footer-right { .box2-main-header-right {
margin-left: 13px;
width: 24px; width: 24px;
height: 24px; height: 24px;
border-radius: 12px;
margin-top: 14px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
} }
.box2-main-main {
width: 1053px;
height: 568px;
margin: 0 auto;
} }
.box3 { .box2-main-footer {
margin-top: 15px; margin-left: 24px;
width: 1103px; width: 1053px;
height: 415px; height: 117px;
border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box3-main {
height: 264px;
overflow-y: auto;
display: flex; display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-left: 21px;
margin-right: 26px;
.box3-item {
margin-top: 12px;
width: 520px;
height: 76px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1); padding-top: 36px;
border-radius: 4px; overflow-x: auto;
display: flex; .box2-main-footer-left {
.box3-item-left { width: 408px;
width: 54px;
height: 54px;
border-radius: 27px;
background: #e7f3ff;
text-align: center; text-align: center;
margin-top: 11px; position: relative;
margin-left: 14px; z-index: 3;
.top {
height: 22px;
display: flex;
justify-content: center;
gap: 6px;
align-items: center;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text { .text {
width: 33px; color: rgba(206, 79, 81, 1);
height: 30px;
color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 400;
line-height: 18px; line-height: 22px;
margin: 11px auto; letter-spacing: 0px;
text-align: left;
} }
} }
.box3-item-right { .bottom {
margin-left: 8px;
width: 433px;
.right-top {
display: flex;
justify-content: space-between;
.title {
margin-top: 13px; margin-top: 13px;
height: 24px; width: 408px;
color: rgba(59, 65, 75, 1); height: 28px;
color: rgba(22, 119, 255, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 18px; font-style: Bold;
font-size: 16px;
font-weight: 700; font-weight: 700;
line-height: 24px; line-height: 24px;
} letter-spacing: 1px;
.tag { text-align: center;
margin-top: 11px; background: url("./assets/images/bg1.png");
width: 72px;
height: 24px;
box-sizing: border-box;
border: 1px solid rgba(255, 163, 158, 1);
border-radius: 4px;
background: rgba(255, 241, 240, 1);
color: rgba(245, 34, 45, 1);
} }
} }
.right-footer { .box2-main-footer-center {
margin-top: 2px; width: 408px;
text-align: center;
margin-left: -10px;
position: relative;
z-index: 2;
.top {
height: 22px;
display: flex; display: flex;
justify-content: space-between; justify-content: center;
.content { gap: 6px;
height: 24px; align-items: center;
color: rgba(95, 101, 108, 1); .icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
color: rgba(206, 79, 81, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-style: Regular;
font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 22px;
width: 353px; letter-spacing: 0px;
overflow: hidden; text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
} }
.time { }
height: 24px; .bottom {
color: rgba(95, 101, 108, 1); margin-top: 13px;
width: 408px;
height: 28px;
color: rgba(19, 168, 168, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-style: Bold;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 700;
width: 78px;
line-height: 24px; line-height: 24px;
overflow: hidden; letter-spacing: 1px;
text-overflow: ellipsis; text-align: center;
white-space: nowrap; background: url("./assets/images/bg2.png");
}
}
}
} }
} }
.box3-footer { .box2-main-footer-right {
width: 1057px; width: 408px;
height: 64px; text-align: center;
box-sizing: border-box; margin-left: -10px;
border: 1px rgba(231, 243, 255, 1); position: relative;
border-radius: 4px; z-index: 1;
background: rgba(246, 251, 255, 1); .top {
margin: 14px auto 0; height: 22px;
padding: 6px 12px 6px 12px;
display: flex; display: flex;
.footer-left { justify-content: center;
width: 19px; gap: 6px;
height: 20px; align-items: center;
margin-top: 16px; .icon {
width: 16px;
height: 16px;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
.footer-center { .text {
margin-left: 13px; color: rgba(206, 79, 81, 1);
width: 964px;
height: 48px;
color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-style: Regular;
font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
}
}
.bottom {
margin-top: 13px;
width: 408px;
height: 28px;
color: rgba(146, 84, 222, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 16px;
font-weight: 700;
line-height: 24px; line-height: 24px;
display: flex; letter-spacing: 1px;
align-items: center; text-align: center;
background: url("./assets/images/bg3.png");
} }
.footer-right {
margin-left: 13px;
width: 24px;
height: 24px;
border-radius: 12px;
margin-top: 14px;
img {
width: 100%;
height: 100%;
} }
} }
} }
......
...@@ -66,9 +66,9 @@ ...@@ -66,9 +66,9 @@
<div class="item-right">{{ item.time }}</div> <div class="item-right">{{ item.time }}</div>
</div> </div>
</div> </div>
<div class="box2-footer"> <!-- <div class="box2-footer">
<img src="./assets/images/more-icon.png" alt="" /> <img src="./assets/images/more-icon.png" alt="" />
</div> </div> -->
</div> </div>
</div> </div>
<div class="right"> <div class="right">
...@@ -368,8 +368,10 @@ onMounted(() => { ...@@ -368,8 +368,10 @@ onMounted(() => {
.box2-main { .box2-main {
margin-top: 3px; margin-top: 3px;
margin-left: 31px; margin-left: 31px;
height: 310px; height: 330px;
width: 1090px; width: 1090px;
overflow: hidden;
overflow-y: auto;
.box2-item { .box2-item {
display: flex; display: flex;
height: 60px; height: 60px;
...@@ -420,16 +422,16 @@ onMounted(() => { ...@@ -420,16 +422,16 @@ onMounted(() => {
} }
} }
} }
.box2-footer { // .box2-footer {
margin: 5px auto 0; // margin: 5px auto 0;
width: 108px; // width: 108px;
height: 32px; // height: 32px;
cursor: pointer; // cursor: pointer;
img { // img {
width: 100%; // width: 100%;
height: 100%; // height: 100%;
} // }
} // }
} }
} }
.right { .right {
......
...@@ -297,7 +297,7 @@ const handleClickBox3Btn = (btn, index) => { ...@@ -297,7 +297,7 @@ const handleClickBox3Btn = (btn, index) => {
eventList.value = box3Data.value[index].newsList.map(val => { eventList.value = box3Data.value[index].newsList.map(val => {
return { return {
time: val.newsDate, time: val.newsDate,
title: newsTitle title: val.newsTitle
}; };
}); });
}; };
...@@ -352,7 +352,7 @@ const handleGetOrgnization = async () => { ...@@ -352,7 +352,7 @@ const handleGetOrgnization = async () => {
eventList.value = res.data[0].newsList.map(val => { eventList.value = res.data[0].newsList.map(val => {
return { return {
time: val.newsDate, time: val.newsDate,
title: newsTitle title: val.newsTitle
}; };
}); });
} else { } else {
...@@ -382,7 +382,12 @@ const handleGetOrgnization = async () => { ...@@ -382,7 +382,12 @@ const handleGetOrgnization = async () => {
eventList.value = []; eventList.value = [];
} }
}; };
onMounted(() => {
handleGetOrgnization(); handleGetOrgnization();
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -545,13 +550,16 @@ handleGetOrgnization(); ...@@ -545,13 +550,16 @@ handleGetOrgnization();
color: #0a57a6; color: #0a57a6;
} }
.title { .title {
width: 1000px; width: 1020px;
line-height: 48px; line-height: 48px;
margin-left: 13px; margin-left: 5px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.open { .open {
width: 16px; width: 16px;
......
...@@ -2,14 +2,15 @@ ...@@ -2,14 +2,15 @@
<div class="page-container"> <div class="page-container">
<div class="page-header"> <div class="page-header">
<div class="page-header-left"> <div class="page-header-left">
<el-image :src="newsImg" alt="新闻" class="page-header-left-img"></el-image> <el-image :src="summaryInfo.newsImg" alt="新闻" class="page-header-left-img"></el-image>
<div class="page-header-left-top"> <div class="page-header-left-top">
<div class="page-header-left-top-title">众议院共和党人起草新的中国投资限制</div> <div class="page-header-left-top-title">{{ summaryInfo.newsTitle }}</div>
<div class="page-header-left-top-en">House Republicans draft new China investment curbs</div> <div class="page-header-left-top-en">{{ summaryInfo.newsETitle }}</div>
<div class="page-header-left-top-desc"> <div class="page-header-left-top-desc">
2025年11月11日 10:33 · 福克斯新闻网 <div class="text">{{ summaryInfo.newsDateTime }} · {{ summaryInfo.newsOrg }}</div>
<el-tag type="primary">生物科技</el-tag> <div class="tag-box">
<el-tag type="primary">人工智能</el-tag> <div class="tag" v-for="(tag, index) in summaryInfo.industryList" :key="index">{{ tag }}</div>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -168,7 +169,9 @@ ...@@ -168,7 +169,9 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import { getNewsSummary, getNewsContent, getNewsEvent, getRelationNews } from "@/api/news/newsDetail";
import CustomContainer from "@/components/Container/index.vue"; import CustomContainer from "@/components/Container/index.vue";
import NewsList from "@/views/exportControl/components/news.vue"; import NewsList from "@/views/exportControl/components/news.vue";
import Graph from "./relation.vue"; import Graph from "./relation.vue";
...@@ -179,15 +182,66 @@ import dotIcon from "@/assets/images/dot.png"; ...@@ -179,15 +182,66 @@ import dotIcon from "@/assets/images/dot.png";
import newsImg1 from "@/assets/images/news-image-1.png"; import newsImg1 from "@/assets/images/news-image-1.png";
import newsImg2 from "@/assets/images/news-image-2.png"; import newsImg2 from "@/assets/images/news-image-2.png";
import newsImg3 from "@/assets/images/news-image-3.png"; import newsImg3 from "@/assets/images/news-image-3.png";
import newsImg4 from "@/assets/images/news-img.png"; import newsImg4 from "@/assets/images/news-img.png";
const route = useRoute();
const summaryInfo = ref({
newsImg: "",
newsTitle: "",
newsETitle: "",
newsDateTime: "",
newsOrg: "",
industryList: [],
newsSrc: "",
newsId: ""
});
const handleGetNewsSummary = async () => {
const params = {
newsId: route.query.newsId
};
try {
const res = await getNewsSummary(params);
console.log("新闻全局信息", res);
if (res.code === 200 && res.data) {
summaryInfo.value = res.data;
summaryInfo.value.newsDateTime = summaryInfo.value.newsDateTime.replace("T", " ");
}
} catch (error) {}
};
const highlightEntities = ref(false); const highlightEntities = ref(false);
const handleToDetail = () => { const handleToDetail = () => {
// window.open("https://www.foxnews.com/technology/house-republicans-draft-new-china-investment-curbs"); // window.open("https://www.foxnews.com/technology/house-republicans-draft-new-china-investment-curbs");
}; };
// 历次制裁过程 // 新闻内容
const newsContentInfo = ref({
newsId: "",
newsDate: "",
newsContent: "",
newsTitle: "",
newsOrg: "",
newsImage: ""
})
const handleGetNewsContent = async () => {
const params = {
newsId: route.query.newsId
}
try {
const res = await getNewsContent(params)
console.log('新闻内容', res);
if(res.code === 200 && res.data) {
newsContentInfo.value = res.data
}
} catch (error) {
}
}
// 事件脉络
const sanctionProcessList = ref([ const sanctionProcessList = ref([
{ {
title: "减税与就业法案的出台与立法博弈", title: "减税与就业法案的出台与立法博弈",
...@@ -215,7 +269,23 @@ const sanctionProcessList = ref([ ...@@ -215,7 +269,23 @@ const sanctionProcessList = ref([
content: "法案通过恰逢美国对多国“90天关税暂缓期”即将到期(2025年7月9日)。欧盟、..." content: "法案通过恰逢美国对多国“90天关税暂缓期”即将到期(2025年7月9日)。欧盟、..."
} }
]); ]);
const handleGetNewsEvent = async () => {
const params = {
newsId: route.query.newsId
};
try {
const res = await getNewsEvent(params);
console.log("事件脉络", res);
if (res.code === 200 && res.data) {
} else {
sanctionProcessList.value = [];
}
} catch (error) {
sanctionProcessList.value = [];
}
};
// 相关新闻
const customNewsData = ref([ const customNewsData = ref([
{ {
image: newsImg4, image: newsImg4,
...@@ -246,6 +316,28 @@ const customNewsData = ref([ ...@@ -246,6 +316,28 @@ const customNewsData = ref([
description: "2017-08-30 · Channel NewsAsia..." description: "2017-08-30 · Channel NewsAsia..."
} }
]); ]);
const handleGetRelationNews = async () => {
const params = {
newsId: route.query.newsId
};
try {
const res = await getRelationNews(params);
console.log("相关新闻", res);
if (res.code === 200 && res.data) {
} else {
customNewsData.value = [];
}
} catch (error) {
customNewsData.value = [];
}
};
onMounted(() => {
handleGetNewsSummary();
handleGetNewsContent()
handleGetNewsEvent();
handleGetRelationNews();
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
...@@ -280,25 +372,59 @@ const customNewsData = ref([ ...@@ -280,25 +372,59 @@ const customNewsData = ref([
justify-content: flex-start; justify-content: flex-start;
gap: 5px; gap: 5px;
&-title { &-title {
color: rgba(59, 65, 75, 1);
height: 32px;
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 24px; font-size: 24px;
font-weight: 700; font-weight: 700;
// margin-bottom: 10px; line-height: 32px;
color: rgba(59, 65, 75, 1); letter-spacing: 0px;
text-align: left;
} }
&-en { &-en {
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
// margin-bottom: 10px; line-height: 24px;
color: rgba(59, 65, 75, 1); letter-spacing: 0px;
text-align: left;
} }
&-desc { &-desc {
height: 24px;
display: flex;
gap: 12px;
.text {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
color: rgba(95, 101, 108, 1); line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
.tag-box {
height: 24px;
display: flex; display: flex;
align-items: center; gap: 4px;
justify-content: center; .tag {
gap: 5px; height: 24px;
line-height: 24px;
padding: 0 8px;
border-radius: 4px;
background: rgba(231, 243, 255, 1);
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
letter-spacing: 0px;
}
}
} }
} }
} }
......
...@@ -13,13 +13,13 @@ ...@@ -13,13 +13,13 @@
<div class="main"> <div class="main">
<div class="main-header"> <div class="main-header">
<div <div
v-for="(item, index) in btnList" v-for="(item, index) in areaList"
:key="index" :key="index"
class="header-btn" class="header-btn"
:class="{ headerBtnSelect: btnSelect === item }" :class="{ headerBtnSelect: areaActive === item.id }"
@click="changeBtn(item)" @click="changeModule(item)"
> >
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
<div class="content-box"> <div class="content-box">
...@@ -46,56 +46,76 @@ ...@@ -46,56 +46,76 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, onMounted } from "vue";
import Index from "../innovationSubject/index.vue"; import { getAreaList, getTodayNewByArea } from "@/api/news/newsBrief";
import { ElMessage } from "element-plus";
const btnList = ref(["全部", "军事", "政治", "经济", "科技", "涉我"]); // 模块类别
const btnSelect = ref("全部"); const areaList = ref([]);
const HeadlinesData = ref([
{ const areaActive = ref("");
title: "黎巴嫩真主党指责美国破坏黎稳定 谴责以色列“蓄意挑衅”",
from: "人民网", const handleGetTodayNewsByArea = async () => {
time: "2025-10-05", const params = {
tag: ["以色列", "美国"], industryId: areaActive.value
image: "/testData/HeadlinesData-img.png" };
}, try {
{ const res = await getTodayNewByArea(params);
title: "IMF上调中东和北非地区经济增长预期", console.log("领域今日要闻", res);
from: "CNN", if (res.code === 200 && res.data) {
time: "2025-10-05", HeadlinesData.value = res.data;
tag: ["经济", "中东", "IMF"], } else {
image: "/testData/HeadlinesData-img.png" ElMessage.error(res.message);
}, HeadlinesData.value = [];
{ }
title: "日本外务省亚洲大洋洲局局长金井正彰启程访华 预计18日与中方会面", } catch (error) {
from: "人民网", HeadlinesData.value = [];
time: "2025-10-05", }
tag: ["日本", "访华"], };
image: "/testData/HeadlinesData-img.png"
}, const handleGetModuleList = async () => {
{ try {
title: "韩日因独岛主权争议暂停本月联合搜救演习", const res = await getAreaList();
from: "凤凰网", console.log("领域列表", res);
time: "2025-10-05", if (res.code === 200 && res.data) {
tag: ["独岛", "联合军演", "韩国", "日本"], areaList.value = res.data;
image: "/testData/HeadlinesData-img.png" areaActive.value = areaList.value[0].id;
}, handleGetTodayNewsByArea();
{
title: "美“福特”号航母抵达加勒比海 于委内瑞拉附近展开大规模军事集结",
from: "央视网",
time: "2025-10-05",
tag: ["美国", "航母", "加勒比海"],
image: "/testData/HeadlinesData-img.png"
} }
} catch (error) {}
};
const HeadlinesData = ref([
// {
// title: "黎巴嫩真主党指责美国破坏黎稳定 谴责以色列“蓄意挑衅”",
// from: "人民网",
// time: "2025-10-05",
// tag: ["以色列", "美国"],
// image: "/testData/HeadlinesData-img.png"
// },
// {
// title: "IMF上调中东和北非地区经济增长预期",
// from: "CNN",
// time: "2025-10-05",
// tag: ["经济", "中东", "IMF"],
// image: "/testData/HeadlinesData-img.png"
// }
]); ]);
function changeBtn(btn) {
btnSelect.value = btn; function changeModule(btn) {
areaActive.value = btn.id;
handleGetTodayNewsByArea();
} }
const emit = defineEmits(["back"]); const emit = defineEmits(["back"]);
function back() { function back() {
emit("back", "home"); emit("back", "home");
} }
onMounted(() => {
handleGetModuleList();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
// @import url("./style.css"); // @import url("./style.css");
...@@ -180,8 +200,9 @@ function back() { ...@@ -180,8 +200,9 @@ function back() {
border-radius: 10px; border-radius: 10px;
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
.main-header { .main-header {
height: 64px; // height: 64px;
display: flex; display: flex;
flex-wrap: wrap;
gap: 16px; gap: 16px;
padding-top: 24px; padding-top: 24px;
padding-left: 24px; padding-left: 24px;
...@@ -190,6 +211,7 @@ function back() { ...@@ -190,6 +211,7 @@ function back() {
line-height: 40px; line-height: 40px;
padding: 0 20px; padding: 0 20px;
border-radius: 32px; border-radius: 32px;
border: 1px solid rgba(32, 33, 35, 0.07);
background: rgba(32, 33, 35, 0.07); background: rgba(32, 33, 35, 0.07);
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -197,6 +219,7 @@ function back() { ...@@ -197,6 +219,7 @@ function back() {
font-weight: 400; font-weight: 400;
letter-spacing: 0px; letter-spacing: 0px;
text-align: center; text-align: center;
cursor: pointer;
} }
.headerBtnSelect { .headerBtnSelect {
box-sizing: border-box; box-sizing: border-box;
......
...@@ -13,31 +13,32 @@ ...@@ -13,31 +13,32 @@
<div class="main"> <div class="main">
<div class="main-header"> <div class="main-header">
<div <div
v-for="(item, index) in btnList" v-for="(item, index) in areaList"
:key="index" :key="index"
class="header-btn" class="header-btn"
:class="{ headerBtnSelect: btnSelect === item }" :class="{ headerBtnSelect: moduleActive === item.id }"
@click="changeBtn(item)" @click="changeArea(item)"
> >
{{ item }} {{ item.name }}
</div> </div>
</div> </div>
<div class="content-box"> <div class="content-box">
<div class="item" v-for="(item, index) in HeadlinesData" :key="index"> <div class="item" v-for="(item, index) in HeadlinesData" :key="index">
<div class="item-left"> <div class="item-left">
<div class="title">{{ item.title }}</div> <div class="title">{{ item.newsTitle }}</div>
<div class="content"> <div class="content">
<div class="source">新闻来源: {{ item.from }}</div> <div class="source">新闻来源: {{ item.newsOrg }}</div>
<div class="time">发表时间:{{ item.time }}</div> <div class="time">发表时间:{{ item.newsDate }}</div>
</div> </div>
<div class="tag-box"> <div class="tag-box">
<div v-for="(tag, index) in item.tag" class="tag" :key="index"> <div v-for="(tag, index) in item.industryList" class="tag" :key="index">
{{ tag }} {{ tag }}
</div> </div>
</div> </div>
</div> </div>
<div class="item-right"> <div class="item-right">
<img :src="`src/assets/icons/arrow-${item.arrow}.png`" /> <img v-if="item.hot" :src="`src/assets/icons/arrow-0.png`" />
<img v-else :src="`src/assets/icons/arrow-1.png`" />
</div> </div>
</div> </div>
</div> </div>
...@@ -46,55 +47,75 @@ ...@@ -46,55 +47,75 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, onMounted } from "vue";
import { getAreaList, getHotNewsByArea } from "@/api/news/newsBrief";
import { ElMessage } from "element-plus";
const btnList = ref(["全部", "军事", "政治", "经济", "敌我"]); // 模块类别
const btnSelect = ref("新闻纵览"); const areaList = ref([]);
const HeadlinesData = ref([ const moduleActive = ref("");
{
title: "黎巴嫩真主党指责美国破坏黎稳定 谴责以色列“蓄意挑衅”", const handleGetHotNewsByArea = async () => {
from: "人民网", const params = {
time: "2025-10-05", industryId: moduleActive.value
tag: ["以色列", "美国"], };
arrow: "0" try {
}, const res = await getHotNewsByArea(params);
{ console.log("领域中美博弈专题", res);
title: "IMF上调中东和北非地区经济增长预期", if (res.code === 200 && res.data) {
from: "CNN", HeadlinesData.value = res.data;
time: "2025-10-05", } else {
tag: ["经济", "中东", "IMF"], ElMessage.error(res.message);
arrow: "1" HeadlinesData.value = [];
}, }
{ } catch (error) {
title: "日本外务省亚洲大洋洲局局长金井正彰启程访华 预计18日与中方会面", HeadlinesData.value = [];
from: "人民网",
time: "2025-10-05",
tag: ["日本", "访华"],
arrow: "1"
},
{
title: "韩日因独岛主权争议暂停本月联合搜救演习",
from: "凤凰网",
time: "2025-10-05",
tag: ["独岛", "联合军演", "韩国", "日本"],
arrow: "0"
},
{
title: "美“福特”号航母抵达加勒比海 于委内瑞拉附近展开大规模军事集结",
from: "央视网",
time: "2025-10-05",
tag: ["美国", "航母", "加勒比海"],
arrow: "0"
} }
};
const handleGetModuleList = async () => {
try {
const res = await getAreaList();
console.log("领域列表", res);
if (res.code === 200 && res.data) {
areaList.value = res.data;
moduleActive.value = areaList.value[0].id;
handleGetHotNewsByArea();
}
} catch (error) {}
};
const HeadlinesData = ref([
// {
// title: "黎巴嫩真主党指责美国破坏黎稳定 谴责以色列“蓄意挑衅”",
// from: "人民网",
// time: "2025-10-05",
// tag: ["以色列", "美国"],
// arrow: "0"
// },
// {
// title: "IMF上调中东和北非地区经济增长预期",
// from: "CNN",
// time: "2025-10-05",
// tag: ["经济", "中东", "IMF"],
// arrow: "1"
// },
]); ]);
function changeBtn(btn) { function changeArea(area) {
btnSelect.value = btn; moduleActive.value = area.id;
handleGetHotNewsByArea()
} }
const emit = defineEmits(["back"]); const emit = defineEmits(["back"]);
function back() { function back() {
emit("back", "home"); emit("back", "home");
} }
onMounted(() => {
handleGetModuleList();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.newsBrief-page { .newsBrief-page {
...@@ -182,8 +203,9 @@ function back() { ...@@ -182,8 +203,9 @@ function back() {
border-radius: 10px; border-radius: 10px;
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
.main-header { .main-header {
height: 64px; // height: 64px;
display: flex; display: flex;
flex-wrap: wrap;
gap: 16px; gap: 16px;
padding-top: 24px; padding-top: 24px;
padding-left: 24px; padding-left: 24px;
...@@ -192,6 +214,7 @@ function back() { ...@@ -192,6 +214,7 @@ function back() {
line-height: 40px; line-height: 40px;
padding: 0 20px; padding: 0 20px;
border-radius: 32px; border-radius: 32px;
border: 1px solid rgba(32, 33, 35, 0.07);
background: rgba(32, 33, 35, 0.07); background: rgba(32, 33, 35, 0.07);
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -199,6 +222,7 @@ function back() { ...@@ -199,6 +222,7 @@ function back() {
font-weight: 400; font-weight: 400;
letter-spacing: 0px; letter-spacing: 0px;
text-align: center; text-align: center;
cursor: pointer;
} }
.headerBtnSelect { .headerBtnSelect {
box-sizing: border-box; box-sizing: border-box;
...@@ -216,7 +240,7 @@ function back() { ...@@ -216,7 +240,7 @@ function back() {
overflow-y: auto; overflow-y: auto;
.item { .item {
width: 952px; width: 952px;
height: 114px; max-height: 114px;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
......
...@@ -10,18 +10,20 @@ ...@@ -10,18 +10,20 @@
<div class="btn-box"> <div class="btn-box">
<div <div
v-for="(item, index) in btnList" v-for="(item, index) in moduleList"
:key="index" :key="index"
:class="btnSelect !== item ? 'header-btn' : 'header-btn-select'" :class="moduleActiveId !== item.moduleId ? 'header-btn' : 'header-btn-select'"
@click="changeBtn(item)" @click="handleToWorldHot(item)"
@mouseenter="handleActiveModule(true, item)"
@mouseleave="handleActiveModule(false, item)"
> >
<div class="btn-box-text">{{ item }}</div> <div class="btn-box-text">{{ item.moduleName }}</div>
<div class="btn-box-icon"> <div class="btn-box-icon">
<img v-if="btnSelect === item" src="@/assets/icons/btn-arrow-right-active.png" alt="" /> <img v-if="moduleActiveId === item.moduleId" src="@/assets/icons/btn-arrow-right-active.png" alt="" />
<img v-else src="@/assets/icons/btn-arrow-right.png" alt="" /> <img v-else src="@/assets/icons/btn-arrow-right.png" alt="" />
</div> </div>
</div> </div>
<div class="header-btn-more"> <div class="header-btn-more" v-if="moduleList.length">
<img src="@/assets/icons/adjustment.png" /> <img src="@/assets/icons/adjustment.png" />
</div> </div>
</div> </div>
...@@ -62,20 +64,28 @@ ...@@ -62,20 +64,28 @@
<div class="box"> <div class="box">
<div class="box-header"> <div class="box-header">
<div class="box-header-img"><img src="@/assets/icons/subject-icon.png" /></div> <div class="box-header-img"><img src="@/assets/icons/subject-icon.png" /></div>
<div class="box-header-title" @click="changePage('subject')">中美博弈专题</div> <div class="box-header-title">中美博弈专题</div>
</div> </div>
<div class="divider"></div> <div class="divider"></div>
<div v-for="(item, index) in subjectData" :key="index"> <div v-for="(item, index) in subjectData" :key="index">
<div class="subject-line"> <div class="subject-line">
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<div class="subject-line-id" :class="{ subjectLineId1: index===0, subjectLineId2: index === 1, subjectLineId3: index === 2 }"> <div
class="subject-line-id"
:class="{
subjectLineId1: index === 0,
subjectLineId2: index === 1,
subjectLineId3: index === 2
}"
>
{{ index <= 2 ? index + 1 : "•" }} {{ index <= 2 ? index + 1 : "•" }}
</div> </div>
<div class="text" :class="{ textTop: index < 3 }"> <div class="text" :class="{ textTop: index < 3 }">
{{ item.text }} {{ item.newsTitle }}
</div> </div>
</div> </div>
<img :src="`src/assets/icons/arrow-${item.arrow}.png`" /> <img v-if="item.hot" :src="`src/assets/icons/arrow-0.png`" />
<img v-else :src="`src/assets/icons/arrow-1.png`" />
</div> </div>
</div> </div>
</div> </div>
...@@ -88,15 +98,30 @@ ...@@ -88,15 +98,30 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, onMounted } from "vue";
import { getMoudleType, getTodayNews, getHotNews } from "@/api/news/newsBrief";
import { useRoute } from "vue-router";
import Headlines from "./Headlines.vue"; import Headlines from "./Headlines.vue";
import Subject from "./Subject.vue"; import Subject from "./Subject.vue";
// import style from './style.css' // import style from './style.css'
const route = useRoute();
//顶部数据搜索 //顶部数据搜索
const searchInput = ref(""); const searchInput = ref("");
const btnList = ref(["新闻纵览", "焦点新闻", "全球热点", "军事热点", "台湾动向", "美国政治", "亚洲局势", "东亚动态"]); const moduleList = ref([]);
const btnSelect = ref("新闻纵览"); const moduleActiveId = ref("");
const handleGetModuleType = async () => {
try {
const res = await getMoudleType();
console.log("模块类别", res);
if (res.code === 200 && res.data) {
moduleList.value = res.data;
}
} catch (error) {}
};
// 今日要闻
const HeadlinesData = ref([ const HeadlinesData = ref([
{ {
title: "黎巴嫩真主党指责美国破坏黎稳定 谴责以色列“蓄意挑衅”", title: "黎巴嫩真主党指责美国破坏黎稳定 谴责以色列“蓄意挑衅”",
...@@ -134,32 +159,62 @@ const HeadlinesData = ref([ ...@@ -134,32 +159,62 @@ const HeadlinesData = ref([
image: "/testData/HeadlinesData-img.png" image: "/testData/HeadlinesData-img.png"
} }
]); ]);
const handleGetTodayNews = async () => {
function changeBtn(btn) { try {
btnSelect.value = btn; const res = await getTodayNews();
} console.log("今日要闻", res);
if (res.code === 200 && res.data) {
} else {
HeadlinesData.value = [];
}
} catch (error) {
HeadlinesData.value = [];
}
};
//当前页面显示 //当前页面显示
const showPage = ref("home"); const showPage = ref("home");
function changePage(page) { const changePage = page => {
console.log(page); console.log(page);
showPage.value = page; showPage.value = page;
} };
//博弈专题新闻数据 //博弈专题新闻数据
const subjectData = ref([ const subjectData = ref([
{ id: 1, text: "乌克兰与法国签署意向书 将获 100 架“阵风”战机及多套防空系统", arrow: 0 }, // { id: 1, text: "乌克兰与法国签署意向书 将获 100 架“阵风”战机及多套防空系统", arrow: 0 },
{ id: 2, text: "安理会通过涉加沙决议 建立和平委员会作为过渡行政机构", arrow: 1 }, // { id: 2, text: "安理会通过涉加沙决议 建立和平委员会作为过渡行政机构", arrow: 1 },
{ id: 3, text: "日本首相高市早苗涉台及修“无核三原则”言论遭多方强烈反对", arrow: 1 }, // { id: 3, text: "日本首相高市早苗涉台及修“无核三原则”言论遭多方强烈反对", arrow: 1 },
{ id: 4, text: "美“福特”号航母打击群进入加勒比海 委方谴责其意图策动政权更迭", arrow: 1 }, // { id: 4, text: "美“福特”号航母打击群进入加勒比海 委方谴责其意图策动政权更迭", arrow: 1 },
{ id: 5, text: "BBC回应特朗普10亿-50亿美元索赔诉讼 称诽谤指控无依据", arrow: 1 }, // { id: 5, text: "BBC回应特朗普10亿-50亿美元索赔诉讼 称诽谤指控无依据", arrow: 1 },
{ id: 6, text: "俄军打击乌142个区域设施 乌军击落或压制91架俄无人机", arrow: 1 }, // { id: 6, text: "俄军打击乌142个区域设施 乌军击落或压制91架俄无人机", arrow: 1 },
{ id: 7, text: "中国女法官张玲玲以第一高票当选联合国上诉法庭法官", arrow: 0 },
{ id: 8, text: "美股三大股指17日收盘普跌 比特币跌破92000美元", arrow: 1 },
{ id: 9, text: "高盛大幅下调2026年布伦特和WTI原油价格预测", arrow: 1 },
{ id: 10, text: "2026米兰冬奥会火炬传递完整路线公布 将穿越意大利全部20个大区", arrow: 1 },
{ id: 11, text: "特朗普宣称若重掌白宫将推动美国开展自1992年以来首次核试验", arrow: 1 },
{ id: 12, text: "欧盟发布2025年秋季经济预测 欧元区今年GDP预计增长1.3%", arrow: 1 }
]); ]);
const handleGetHotNews = async () => {
try {
const res = await getHotNews();
console.log("中美博弈专题", res);
if (res.code === 200 && res.data) {
subjectData.value = res.data;
} else {
subjectData.value = [];
}
} catch (error) {
subjectData.value = [];
}
};
const handleActiveModule = (isIn, module) => {
moduleActiveId.value = isIn ? module.moduleId : "";
};
const handleToWorldHot = () => {
showPage.value = 'subject'
moduleActiveId.value = ''
};
onMounted(() => {
handleGetModuleType();
handleGetTodayNews();
handleGetHotNews();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import url("./style.css"); @import url("./style.css");
......
...@@ -2,15 +2,14 @@ ...@@ -2,15 +2,14 @@
<div class="home-wrapper"> <div class="home-wrapper">
<div class="home-main"> <div class="home-main">
<div class="home-main-center"> <div class="home-main-center">
<div class="center-center"> <div class="center-center">
<div class="center-header"> <div class="center-header">
<div class="center-header-left"> <div class="center-header-left">
<img class="iconstyle" src="./assets/images/warning.png" ></img> <img class="iconstyle" src="./assets/images/warning.png" />
<div class="center-header-title">风险信号管理</div> <div class="center-header-title">风险信号管理</div>
</div> </div>
<div class="center-header-right"> <div class="center-header-right">
<img class="img" src="./assets/images/danger.png"></img> <img class="img" src="./assets/images/danger.png" />
<div class="text">风险统计</div> <div class="text">风险统计</div>
</div> </div>
</div> </div>
...@@ -19,33 +18,39 @@ ...@@ -19,33 +18,39 @@
<div class="lineitem"> <div class="lineitem">
<div class="item"> <div class="item">
<div class="top"> <div class="top">
<div class="dot" style="background-color: rgba(95, 101, 108, 1);"></div> <div class="dot" style="background-color: rgba(95, 101, 108, 1)"></div>
<div class="text1">本年新增风险</div> <div class="text1">本年新增风险</div>
</div> </div>
<div class="text2" style="color: rgba(95, 101, 108, 1);">219项</div> <div class="text2" style="color: rgba(95, 101, 108, 1)">
{{ basicInfo.yearAdded + " 项" }}
</div>
</div> </div>
<div class="item"> <div class="item">
<div class="top"> <div class="top">
<div class="dot" style="background-color: rgba(95, 101, 108, 1);"></div> <div class="dot" style="background-color: rgba(95, 101, 108, 1)"></div>
<div class="text1">本月新增风险</div> <div class="text1">本月新增风险</div>
</div> </div>
<div class="text2" style="color: rgba(95, 101, 108, 1);">40项</div> <div class="text2" style="color: rgba(95, 101, 108, 1)">
{{ basicInfo.monthAdded + " 项" }}
</div>
</div> </div>
</div> </div>
<div class="lineitem"> <div class="lineitem">
<div class="item"> <div class="item">
<div class="top"> <div class="top">
<div class="dot" style="background-color: rgba(5, 95, 194, 1);"></div> <div class="dot" style="background-color: rgba(5, 95, 194, 1)"></div>
<div class="text1">已处理风险</div> <div class="text1">已处理风险</div>
</div> </div>
<div class="text2" style="color: rgba(5, 95, 194, 1);">212项</div> <div class="text2" style="color: rgba(5, 95, 194, 1)">{{ basicInfo.dealCount + " 项" }}</div>
</div> </div>
<div class="item"> <div class="item">
<div class="top"> <div class="top">
<div class="dot" style="background-color: rgba(206, 79, 81, 1);"></div> <div class="dot" style="background-color: rgba(206, 79, 81, 1)"></div>
<div class="text1">待处理风险</div> <div class="text1">待处理风险</div>
</div> </div>
<div class="text2" style="color: rgba(206, 79, 81, 1);">7项</div> <div class="text2" style="color: rgba(206, 79, 81, 1)">
{{ basicInfo.pendingCount + " 项" }}
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -54,7 +59,6 @@ ...@@ -54,7 +59,6 @@
</div> </div>
</div> </div>
<div class="home-main-footer"> <div class="home-main-footer">
<div class="home-main-footer-main"> <div class="home-main-footer-main">
<div class="left"> <div class="left">
...@@ -64,17 +68,28 @@ ...@@ -64,17 +68,28 @@
<div class="title">{{ "风险类型" }}</div> <div class="title">{{ "风险类型" }}</div>
</div> </div>
<div class="left-box1-main"> <div class="left-box1-main">
<div <el-checkbox
class="time-label" v-model="isRiskTypeCheckedAll"
:indeterminate="isRiskTypeIndeterminate"
@change="handleRiskTypeCheckAllChange"
class="checkbox-all"
>
全部类型
</el-checkbox>
<el-checkbox-group
class="checkbox-group"
v-model="checkedRiskType"
@change="handleRiskTypeChange"
>
<el-checkbox
v-for="(item, index) in riskType" v-for="(item, index) in riskType"
:key="index" :key="index"
:label="item"
class="filter-checkbox"
> >
<el-checkbox {{ item }}
v-model="item.selected" </el-checkbox>
:label="item.name" </el-checkbox-group>
size="large"
/>
</div>
</div> </div>
</div> </div>
<div class="left-box1"> <div class="left-box1">
...@@ -83,17 +98,28 @@ ...@@ -83,17 +98,28 @@
<div class="title">{{ "风险来源" }}</div> <div class="title">{{ "风险来源" }}</div>
</div> </div>
<div class="left-box1-main"> <div class="left-box1-main">
<div <el-checkbox
class="time-label" v-model="isRiskSourceCheckedAll"
v-for="(item, index) in riskSource" :indeterminate="isRiskSourceIndeterminate"
:key="index" @change="handleRiskSourceCheckAllChange"
class="checkbox-all"
>
全部来源
</el-checkbox>
<el-checkbox-group
class="checkbox-group"
v-model="checkedRiskSource"
@change="handleRiskSourceChange"
> >
<el-checkbox <el-checkbox
v-model="item.selected" v-for="item in riskSource"
:label="item.name" :key="item.id"
size="large" :label="item.id"
/> class="filter-checkbox"
</div> >
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div> </div>
</div> </div>
<div class="left-box1"> <div class="left-box1">
...@@ -102,36 +128,49 @@ ...@@ -102,36 +128,49 @@
<div class="title">{{ "风险等级" }}</div> <div class="title">{{ "风险等级" }}</div>
</div> </div>
<div class="left-box1-main"> <div class="left-box1-main">
<div <el-checkbox
class="time-label" v-model="isRiskDegreeCheckedAll"
v-for="(item, index) in riskDegree" :indeterminate="isRiskDegreeIndeterminate"
:key="index" @change="handleRiskDegreeCheckAllChange"
class="checkbox-all"
>
全部等级
</el-checkbox>
<el-checkbox-group
class="checkbox-group"
v-model="checkedRiskDegree"
@change="handleRiskDegreeChange"
> >
<el-checkbox <el-checkbox
v-model="item.selected" v-for="item in riskDegree"
:key="item.id"
:label="item.name" :label="item.name"
size="large" class="filter-checkbox"
/> >
</div> {{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div> </div>
</div> </div>
<div class="left-box1"> <div class="left-box1">
<div class="left-box1-header"> <div class="left-box1-header">
<div class="icon"></div> <div class="icon"></div>
<div class="title">{{ "设计领域" }}</div> <div class="title">{{ "涉及领域" }}</div>
</div> </div>
<div class="left-box1-main"> <div class="left-box1-main">
<div
class="time-label"
v-for="(item, index) in area"
:key="index"
>
<el-checkbox <el-checkbox
v-model="item.selected" v-model="isAreaCheckedAll"
:label="item.name" :indeterminate="isAreaIndeterminate"
size="large" @change="handleAreaCheckAllChange"
/> class="checkbox-all"
</div> >
全部领域
</el-checkbox>
<el-checkbox-group class="checkbox-group" v-model="checkedArea" @change="handleAreaChange">
<el-checkbox v-for="item in area" :key="item.id" :label="item.name" class="filter-checkbox">
{{ item.name }}
</el-checkbox>
</el-checkbox-group>
</div> </div>
</div> </div>
</div> </div>
...@@ -139,73 +178,90 @@ ...@@ -139,73 +178,90 @@
<div class="right"> <div class="right">
<div class="right-header"> <div class="right-header">
<div class="header-left"> <div class="header-left">
<div class="btn-left" :class="{ btnleftactive: activeBtn === '全部' }" <div
@click="handleClickBtn('全部')"> class="btn-left"
<div class="btn-text" :class="{ btntextactive: activeBtn === '全部' }">全部</div> :class="{ btnleftactive: activeProcessStatusId === item.id }"
</div> @click="handleClickBtn(item)"
<div class="btn-left" :class="{btnleftactive: activeBtn === '未处理'}" v-for="item in processStatusList"
@click="handleClickBtn('未处理')"> :key="item.id"
<div class="btn-text" :class="{btntextactive: activeBtn === '未处理'}">未处理</div> >
<div class="btn-text" :class="{ btntextactive: activeProcessStatusId === item.id }">
{{ item.name }}
</div> </div>
<div class="btn-left" :class="{btnleftactive: activeBtn === '已处理'}"
@click="handleClickBtn('已处理')">
<div class="btn-text" :class="{btntextactive: activeBtn === '已处理'}">已处理</div>
</div> </div>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="searchbox"> <div class="searchbox">
<el-input <el-input
v-model="input" @keyup.enter="handleSearch"
v-model="kewword"
style="width: 268px; height: 100%" style="width: 268px; height: 100%"
placeholder="搜索"/> placeholder="搜索"
<div class="search-btn"></div> />
<div class="search-btn" @click="handleSearch"></div>
</div> </div>
<div class="select-box"> <div class="select-box">
<el-select <div class="paixu-btn" @click="handleSwithSort">
v-model="releaseTime" <div class="icon1">
placeholder="发布时间" <img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" />
style="width: 120px" <img v-else src="@/assets/icons/jiangxu1.png" alt="" />
> </div>
<el-option <div class="text">{{ "发布时间" }}</div>
v-for="item in releaseTimeList" <div class="icon2">
:key="item.value" <img v-if="isSort" src="@/assets/icons/shengxu2.png" alt="" />
:label="item.label" <img v-else src="@/assets/icons/jiangxu2.png" alt="" />
:value="item.value" </div>
/> </div>
</el-select>
</div> </div>
</div> </div>
</div> </div>
<div class="right-main"> <div class="right-main">
<div class="itemlist" v-for="(val, idx) in riskList" :key="idx"> <div class="itemlist" v-for="(val, idx) in riskList" :key="idx">
<div class="item-box">
<div class="box-title"> <div class="box-title">
<div class="risktitle">{{ val.title }}</div> <div class="risktitle">{{ val.title }}</div>
<div class="risktype" :style="{backgroundColor: val.bgcolor,color: val.textcolor}">{{ val.risktype }}</div> <div
class="risktype"
:class="{
risk1: val.risktype === '特别重大风险' || val.risktype === '特别重大',
risk2: val.risktype === '重大风险',
risk3: val.risktype === '一般风险'
}"
>
<div
class="icon"
:class="{
icon1: val.risktype === '特别重大风险' || val.risktype === '特别重大',
icon2: val.risktype === '重大风险',
icon3: val.risktype === '一般风险'
}"
></div>
<div class="text">{{ val.risktype }}</div>
</div>
</div> </div>
<div class="box-source"> <div class="box-source">
<img class="source-pic" :src="val.pic" alt="" /> <img class="source-pic" :src="val.pic ? val.pic : DefaultIcon2" alt="" />
<div class="source-text">{{ val.origin }}</div> <div class="source-text">{{ val.origin + " · " + val.fileType }}</div>
<div class="source-text">{{ val.time }}</div> <div class="source-text">{{ val.time }}</div>
</div> </div>
<div class="desc-box">{{ val.dsc }}</div> <div class="desc-box">{{ val.dsc }}</div>
<div class="tag-box" > <div class="tag-box" v-if="val.tag.length">
<el-tag v-for="tag,index in val.tag" :key="index">{{ tag }}</el-tag> <div class="tag" v-for="(tag, index) in val.tag" :key="index">{{ tag }}</div>
</div>
</div> </div>
<div class="splitline"></div>
</div> </div>
</div> </div>
<div class="right-footer"> <div class="right-footer">
<div class="footer-left"> <div class="footer-left">
{{ "共105项调查" }} {{ `共${totalNum}项调查` }}
</div> </div>
<div class="footer-right"> <div class="footer-right">
<el-pagination <el-pagination
@current-change="handleCurrentChange"
:pageSize="pageSize"
:current-page="currentPage"
:total="totalNum"
background background
layout="prev, pager, next" layout="prev, pager, next"
:total="105"
/> />
</div> </div>
</div> </div>
...@@ -218,281 +274,460 @@ ...@@ -218,281 +274,460 @@
<script setup> <script setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import * as echarts from "echarts"; import { getCountInfo, getDailyCount, getPageQuery } from "@/api/riskSignal/index";
import router from "@/router"; import setChart from "@/utils/setChart";
import getCalendarHeatChart from "./utils/cleandarHeat"; import getCalendarHeatChart from "./utils/cleandarHeat";
import DefaultIcon2 from "@/assets/icons/default-icon2.png";
const activeBtn = ref("全部"); const riskType = ref(["科技法案", "行政令", "智库报告", "出口管制", "投融资限制", "市场准入限制", "规则限制"]);
const handleClickBtn = name => { const isRiskTypeCheckedAll = ref(false);
activeBtn.value = name; const isRiskTypeIndeterminate = ref(true);
const checkedRiskType = ref([]);
const handleRiskTypeCheckAllChange = val => {
checkedRiskType.value = val ? riskType.value : [];
isRiskTypeIndeterminate.value = false;
handleGetPageQuery();
};
const handleRiskTypeChange = val => {
const checkedCount = val.length;
isRiskTypeCheckedAll.value = checkedCount === riskType.value.length;
isRiskTypeIndeterminate.value = checkedCount > 0 && checkedCount < riskType.value.length;
handleGetPageQuery();
}; };
const riskType = ref([ const riskSource = ref([
{ {
name: "科技法案", name: "美国",
selected: true, id: "0502"
}, },
{ {
name: "行政令", name: "韩国",
selected: true, id: "0103"
}, },
{ {
name: "智库报告", name: "日本",
selected: true, id: "0104"
}, },
{ {
name: "出口管制", name: "德国",
selected: true, id: "0216"
}, },
{ {
name: "投融资限制", name: "英国",
selected: true, id: "0217"
}, },
{ {
name: "市场准入限制", name: "法国",
selected: true, id: "0222"
}, },
{ {
name: "规则限制", name: "澳大利亚",
selected: true, id: "0401"
}, }
]); ]);
const isRiskSourceCheckedAll = ref(false);
const isRiskSourceIndeterminate = ref(true);
const checkedRiskSource = ref([]);
const riskSource = ref([ const handleRiskSourceCheckAllChange = val => {
{ checkedRiskSource.value = val
name: "美国", ? riskSource.value.map(item => {
selected: true, return item.id;
}, })
{ : [];
name: "欧盟", isRiskSourceIndeterminate.value = false;
selected: true, handleGetPageQuery();
}, };
{ const handleRiskSourceChange = val => {
name: "日本", const checkedCount = val.length;
selected: true, isRiskSourceCheckedAll.value = checkedCount === riskSource.value.length;
}, isRiskSourceIndeterminate.value = checkedCount > 0 && checkedCount < riskSource.value.length;
{ handleGetPageQuery();
name: "韩国", };
selected: true,
},
]);
const riskDegree = ref([ const riskDegree = ref([
{ {
name: "特别重大风险", name: "特别重大",
selected: true, id: "特别重大"
}, },
{ {
name: "重大风险", name: "重大风险",
selected: true, id: "重大风险"
}, },
{ {
name: "较大风险", name: "较大风险",
selected: true, id: "较大风险"
}, },
{ {
name: "一般风险", name: "一般风险",
selected: true, id: "一般风险"
}, },
{ {
name: "无风险", name: "无风险",
selected: true, id: "无风险"
} }
]); ]);
const isRiskDegreeCheckedAll = ref(false);
const isRiskDegreeIndeterminate = ref(true);
const checkedRiskDegree = ref([]);
const handleRiskDegreeCheckAllChange = val => {
checkedRiskDegree.value = val
? riskDegree.value.map(item => {
return item.id;
})
: [];
isRiskDegreeIndeterminate.value = false;
handleGetPageQuery();
};
const handleRiskDegreeChange = val => {
const checkedCount = val.length;
isRiskDegreeCheckedAll.value = checkedCount === riskDegree.value.length;
isRiskDegreeIndeterminate.value = checkedCount > 0 && checkedCount < riskDegree.value.length;
handleGetPageQuery();
};
const area = ref([ const area = ref([
{ {
name: "人工智能", name: "人工智能",
selected: true, id: 1
}, },
{ {
name: "集成电路", name: "生物科技",
selected: true, id: 2
}, },
{ {
name: "通信网络", name: "新一代通信技术",
selected: true, id: 3
}, },
{ {
name: "量子科技", name: "量子科技",
selected: true, id: 4
}, },
{ {
name: "生物科技", name: "新能源",
selected: true, id: 5
}, },
{ {
name: "能源", name: "集成电路",
selected: true, id: 6
}, },
{ {
name: "航空航天", name: "海洋",
selected: true, id: 7
}, },
{ {
name: "先进制造", name: "先进制造",
selected: true, id: 8
}, },
]);
const releaseTime = ref("发布时间");
const releaseTimeList = ref([
{ {
label: "近半年发布", name: "新材料",
value: "近半年发布", id: 9
}, },
{ {
label: "近一年发布", name: "航空航天",
value: "近一年发布", id: 10
}, },
{ {
label: "近两年发布", name: "深海",
value: "近两年发布", id: 11
}, },
{ {
label: "近三年发布", name: "极地",
value: "近三年发布", id: 12
}, },
{ {
label: "近五年发布", name: "太空",
value: "近五年发布", id: 13
}, },
]);
const riskList = ref([
{ {
title: "扩大实体清单制裁范围,对中企子公司实施同等管制", name: "核",
origin: "美国商务部 · 实体清单", id: 14
time:"2025年11月10日 16:14",
dsc: "任何被列入美国出口管制“实体清单”或“军事最终用户清单”的企业,如果其直接或间接持有另一家公司 ​50%或以上的股权,那么这家被控股的公司也将自动受到与清单上母公司同等的出口管制限制",
tag:["生物科技","人工智能"],
risktype: "·特别重大风险",
pic: "src/views/riskSignal/assets/images/origin1.png",
textcolor:"rgba(206, 79, 81, 1)",
bgcolor:"rgba(206, 79, 81, 0.1)"
}, },
{ {
title: "大而美法案通过国会众议院投票,将提交至总统签署", name: "其他",
origin: "美国国会 · 科技法案", id: 99
time:"2025年11月10日 16:14", }
dsc: "", ]);
tag:["能源","人工智能"],
risktype: "·重大风险", const isAreaCheckedAll = ref(false);
pic: "src/views/riskSignal/assets/images/origin2.png", const isAreaIndeterminate = ref(true);
textcolor:"rgba(255, 149, 77, 1)", const checkedArea = ref([]);
bgcolor:"rgba(255, 149, 77, 0.1)"
}, const handleAreaCheckAllChange = val => {
checkedArea.value = val
? area.value.map(item => {
return item.id;
})
: [];
isAreaIndeterminate.value = false;
handleGetPageQuery();
};
const handleAreaChange = val => {
const checkedCount = val.length;
isAreaCheckedAll.value = checkedCount === area.value.length;
isAreaIndeterminate.value = checkedCount > 0 && checkedCount < area.value.length;
handleGetPageQuery();
};
const processStatusList = ref([
{ {
title: "兰德公司发布智库报告《中美经济竞争:复杂经济和地缘政治关系中的收益和风险》", name: "全部",
origin: "兰德公司 · 科技智库", id: -1
time:"2025年11月10日 16:14",
dsc: "包括经济竞争在内的美中竞争自2017年以来一直在定义美国外交政策。这两个经济体是世界上第一和第二大国家经济体,并且深深交织在一起。改变关系,无论多么必要,可能是昂贵的。因此,美国面临着一项挑战,确保其经济在耦合的战略竞争条件下满足国家的需求。",
tag:["生物科技","人工智能","集成电路"],
risktype: "·一般风险",
pic: "src/views/riskSignal/assets/images/origin3.png",
textcolor:"rgba(5, 95, 194, 1)",
bgcolor:"rgba(5, 95, 194, 0.1)"
}, },
{ {
title: "美国白宫发布总统政令《关于进一步延长TikTok执法宽限期的行政令》", name: "未处理",
origin: "美国白宫 · 总统政令", id: 0
time:"2025年11月10日 16:14",
dsc: "再次推迟(第四次)对TikTok禁令的执法,新的宽限期截止日为2025年12月16日​。在宽限期内及对于宽限期前的行为,司法部不得强制执行​《保护美国人免受外国对手控制应用程序法》或因此处罚相关实体​(如TikTok及其分发平台)。",
tag:["人工智能"],
risktype: "·一般风险",
pic: "src/views/riskSignal/assets/images/origin2.png",
textcolor:"rgba(5, 95, 194, 1)",
bgcolor:"rgba(5, 95, 194, 0.1)"
}, },
{ {
title: "美国财政部更新《特别指定国民清单》", name: "处理中",
origin: "美国财政部 · 特别指定国民清单", id: 1
time:"2025年11月10日 16:14",
dsc: "",
tag:["生物科技"],
risktype: "·特别重大风险",
pic: "src/views/riskSignal/assets/images/origin4.png",
textcolor:"rgba(206, 79, 81, 1)",
bgcolor:"rgba(206, 79, 81, 0.1)"
}, },
{ {
title: "美国FDA针对两家中国第三方检测机构的数据完整性问题采取行动", name: "已处理",
origin: "美国食品药品监督管理局 · 规则限制", id: 2
time:"2025年11月10日 16:14",
dsc: "FDA因发现数据伪造或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏州大学卫生与环境技术研究所)正式发出“一般信函”。",
tag:["生物科技","人工智能"],
risktype: "·特别重大风险",
pic: "src/views/riskSignal/assets/images/origin5.png",
textcolor:"rgba(206, 79, 81, 1)",
bgcolor:"rgba(206, 79, 81, 0.1)"
} }
]); ]);
const activeProcessStatusId = ref(-1);
// 绘制echarts图表 const handleClickBtn = item => {
const setChart = (option, chartId) => { activeProcessStatusId.value = item.id;
let chartDom = document.getElementById(chartId); handleGetPageQuery();
chartDom.removeAttribute("_echarts_instance_");
let chart = echarts.init(chartDom);
chart.setOption(option);
return chart;
}; };
const riskList = ref([
// {
// title: "扩大实体清单制裁范围,对中企子公司实施同等管制",
// origin: "美国商务部",
// fileType: "实体清单",
// time: "2025年11月10日 16:14",
// dsc: "任何被列入美国出口管制“实体清单”或“军事最终用户清单”的企业,如果其直接或间接持有另一家公司 ​50%或以上的股权,那么这家被控股的公司也将自动受到与清单上母公司同等的出口管制限制",
// tag: ["生物科技", "人工智能"],
// risktype: "特别重大风险",
// pic: "src/views/riskSignal/assets/images/origin1.png"
// }
// {
// title: "大而美法案通过国会众议院投票,将提交至总统签署",
// origin: "美国国会 · 科技法案",
// time: "2025年11月10日 16:14",
// dsc: "",
// tag: ["能源", "人工智能"],
// risktype: "重大风险",
// pic: "src/views/riskSignal/assets/images/origin2.png",
// textcolor: "rgba(255, 149, 77, 1)",
// bgcolor: "rgba(255, 149, 77, 0.1)"
// },
// {
// title: "兰德公司发布智库报告《中美经济竞争:复杂经济和地缘政治关系中的收益和风险》",
// origin: "兰德公司 · 科技智库",
// time: "2025年11月10日 16:14",
// dsc: "包括经济竞争在内的美中竞争自2017年以来一直在定义美国外交政策。这两个经济体是世界上第一和第二大国家经济体,并且深深交织在一起。改变关系,无论多么必要,可能是昂贵的。因此,美国面临着一项挑战,确保其经济在耦合的战略竞争条件下满足国家的需求。",
// tag: ["生物科技", "人工智能", "集成电路"],
// risktype: "一般风险",
// pic: "src/views/riskSignal/assets/images/origin3.png",
// textcolor: "rgba(5, 95, 194, 1)",
// bgcolor: "rgba(5, 95, 194, 0.1)"
// },
// {
// title: "美国白宫发布总统政令《关于进一步延长TikTok执法宽限期的行政令》",
// origin: "美国白宫 · 总统政令",
// time: "2025年11月10日 16:14",
// dsc: "再次推迟(第四次)对TikTok禁令的执法,新的宽限期截止日为2025年12月16日​。在宽限期内及对于宽限期前的行为,司法部不得强制执行​《保护美国人免受外国对手控制应用程序法》或因此处罚相关实体​(如TikTok及其分发平台)。",
// tag: ["人工智能"],
// risktype: "一般风险",
// pic: "src/views/riskSignal/assets/images/origin2.png",
// textcolor: "rgba(5, 95, 194, 1)",
// bgcolor: "rgba(5, 95, 194, 0.1)"
// },
// {
// title: "美国财政部更新《特别指定国民清单》",
// origin: "美国财政部 · 特别指定国民清单",
// time: "2025年11月10日 16:14",
// dsc: "",
// tag: ["生物科技"],
// risktype: "特别重大风险",
// pic: "src/views/riskSignal/assets/images/origin4.png",
// textcolor: "rgba(206, 79, 81, 1)",
// bgcolor: "rgba(206, 79, 81, 0.1)"
// },
// {
// title: "美国FDA针对两家中国第三方检测机构的数据完整性问题采取行动",
// origin: "美国食品药品监督管理局 · 规则限制",
// time: "2025年11月10日 16:14",
// dsc: "FDA因发现数据伪造或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏州大学卫生与环境技术研究所)正式发出“一般信函”。",
// tag: ["生物科技", "人工智能"],
// risktype: "特别重大风险",
// pic: "src/views/riskSignal/assets/images/origin5.png",
// textcolor: "rgba(206, 79, 81, 1)",
// bgcolor: "rgba(206, 79, 81, 0.1)"
// }
]);
const calendarData = ref([ const calendarData = ref([
["2025-01-01", 20], // ["2025-01-01", 20],
["2025-01-05", 120], // ["2025-01-05", 120],
["2025-01-09", 220], // ["2025-01-09", 220],
["2025-01-15", 320], // ["2025-01-15", 320],
["2025-01-20", 120], // ["2025-01-20", 120],
["2025-01-24", 420], // ["2025-01-24", 420],
["2025-02-05", 80], // ["2025-02-05", 80],
["2025-02-08", 280], // ["2025-02-08", 280],
["2025-02-18", 480], // ["2025-02-18", 480],
["2025-02-11", 420], // ["2025-02-11", 420],
["2025-02-21", 320], // ["2025-02-21", 320],
["2025-03-05", 160], // ["2025-03-05", 160],
["2025-03-09", 260], // ["2025-03-09", 260],
["2025-03-19", 460], // ["2025-03-19", 460],
["2025-03-26", 430], // ["2025-03-26", 430],
["2025-04-01", 70], // ["2025-04-01", 70],
["2025-04-05", 170], // ["2025-04-05", 170],
["2025-04-11", 270], // ["2025-04-11", 270],
["2025-04-18", 370], // ["2025-04-18", 370],
["2025-05-05", 210], // ["2025-05-05", 210],
["2025-05-09", 210], // ["2025-05-09", 210],
["2025-05-15", 410], // ["2025-05-15", 410],
["2025-05-22", 480], // ["2025-05-22", 480],
["2025-06-06", 45], // ["2025-06-06", 45],
["2025-06-09", 415], // ["2025-06-09", 415],
["2025-06-16", 245], // ["2025-06-16", 245],
["2025-06-19", 332], // ["2025-06-19", 332],
["2025-07-04", 127], // ["2025-07-04", 127],
["2025-07-09", 327], // ["2025-07-09", 327],
["2025-07-24", 427], // ["2025-07-24", 427],
["2025-08-08", 150], // ["2025-08-08", 150],
["2025-08-11", 250], // ["2025-08-11", 250],
["2025-08-15", 350], // ["2025-08-15", 350],
["2025-08-22", 460], // ["2025-08-22", 460],
["2025-09-10", 480], // ["2025-09-10", 480],
["2025-09-18", 312], // ["2025-09-18", 312],
["2025-10-15", 60], // ["2025-10-15", 60],
["2025-10-19", 80], // ["2025-10-19", 80],
["2025-10-21", 190], // ["2025-10-21", 190]
]); ]);
onMounted(async () => { // 基本统计信息
const basicInfo = ref({
dealCount: 0,
monthAdded: 0,
pendingCount: 0,
yearAdded: 0
});
const handleGetCountInfo = async () => {
try {
const res = await getCountInfo();
console.log("基本统计信息", res);
if (res.code === 200 && res.data) {
basicInfo.value = res.data;
}
} catch (error) {}
};
// 每日统计信息
const handleGetDailyCount = async () => {
try {
const res = await getDailyCount();
console.log("每日统计信息", res);
if (res.code === 200 && res.data) {
calendarData.value = res.data.map(item => {
return [item.day, item.count];
});
}
} catch (error) {}
};
const handleCleandarChart = async () => {
await handleGetDailyCount();
let chartCalendar = getCalendarHeatChart(calendarData.value); let chartCalendar = getCalendarHeatChart(calendarData.value);
setChart(chartCalendar, "chartCalendar"); setChart(chartCalendar, "chartCalendar");
};
//
const isSort = ref(true); // true 升序 false 倒序
const handleSwithSort = () => {
isSort.value = !isSort.value;
handleGetPageQuery();
};
// 搜索
const kewword = ref("");
const handleSearch = async () => {
handleGetPageQuery();
};
// 风险信号总数
const totalNum = ref(0);
const currentPage = ref(1);
const pageSize = ref(10);
// 处理页码改变事件
const handleCurrentChange = page => {
currentPage.value = page;
handleGetPageQuery();
};
// 按条件分页查询风险信号信息
const handleGetPageQuery = async () => {
let params;
if (activeProcessStatusId.value === -1) {
params = {
riskTypes: checkedRiskType.value,
srcCountryList: checkedRiskSource.value,
riskLevels: checkedRiskDegree.value,
techDomainIds: checkedArea.value,
keywords: kewword.value,
pageNum: currentPage.value,
pageSize: pageSize.value,
sortField: "time",
sortOrder: isSort ? "asc" : "desc"
};
} else {
params = {
riskTypes: checkedRiskType.value,
srcCountryList: checkedRiskSource.value,
riskLevels: checkedRiskDegree.value,
techDomainIds: checkedArea.value,
dealStatus: activeProcessStatusId.value,
keywords: kewword.value,
pageNum: 1,
pageSize: 10,
sortField: "time",
sortOrder: isSort ? "asc" : "desc"
};
}
try {
const res = await getPageQuery(params);
console.log("按条件查询", res);
if (res.code === 200 && res.data) {
totalNum.value = res.data.totalElements;
riskList.value = res.data.content.map(item => {
return {
title: item.titleZh,
origin: item.srcOrgId,
fileType: "暂无数据",
time: item.time,
dsc: item.contentZh,
tag: [],
risktype: item.level,
pic: ""
};
});
}
} catch (error) {
console.error("按条件查询error", error);
}
};
onMounted(async () => {
handleGetCountInfo();
handleCleandarChart();
handleGetPageQuery();
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.el-input__wrapper) { :deep(.el-input__wrapper) {
box-shadow: none; box-shadow: none;
} }
...@@ -521,12 +756,12 @@ onMounted(async () => { ...@@ -521,12 +756,12 @@ onMounted(async () => {
margin-left: 30px; margin-left: 30px;
display: flex; display: flex;
margin-top: 15px; margin-top: 15px;
.iconstyle{ .iconstyle {
width: 27px; width: 27px;
height: 24px; height: 24px;
margin-top: 3px; margin-top: 3px;
} }
.center-header-title{ .center-header-title {
margin-left: 10px; margin-left: 10px;
font-size: 24px; font-size: 24px;
font-weight: 700; font-weight: 700;
...@@ -545,11 +780,11 @@ onMounted(async () => { ...@@ -545,11 +780,11 @@ onMounted(async () => {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
.img{ .img {
width: 16px; width: 16px;
height: 15px; height: 15px;
} }
.text{ .text {
margin-left: 8px; margin-left: 8px;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
...@@ -558,15 +793,15 @@ onMounted(async () => { ...@@ -558,15 +793,15 @@ onMounted(async () => {
} }
} }
} }
.center-middle{ .center-middle {
display: flex; display: flex;
.center-middle-left{ .center-middle-left {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.lineitem{ .lineitem {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.item{ .item {
margin-left: 61px; margin-left: 61px;
margin-top: 33px; margin-top: 33px;
width: 111px; width: 111px;
...@@ -574,17 +809,17 @@ onMounted(async () => { ...@@ -574,17 +809,17 @@ onMounted(async () => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
.top{ .top {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
.dot{ .dot {
width: 6px; width: 6px;
height: 6px; height: 6px;
margin-top: 9px; margin-top: 9px;
margin-right: 7px; margin-right: 7px;
border-radius: 3px; border-radius: 3px;
} }
.text1{ .text1 {
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
...@@ -592,7 +827,7 @@ onMounted(async () => { ...@@ -592,7 +827,7 @@ onMounted(async () => {
text-align: right; text-align: right;
} }
} }
.text2{ .text2 {
font-size: 32px; font-size: 32px;
font-weight: 700; font-weight: 700;
line-height: 42px; line-height: 42px;
...@@ -601,7 +836,7 @@ onMounted(async () => { ...@@ -601,7 +836,7 @@ onMounted(async () => {
} }
} }
} }
.center-middle-right{ .center-middle-right {
width: 1159px; width: 1159px;
height: 189px; height: 189px;
box-sizing: border-box; box-sizing: border-box;
...@@ -652,7 +887,6 @@ onMounted(async () => { ...@@ -652,7 +887,6 @@ onMounted(async () => {
} }
} }
} }
} }
.home-main-footer-main { .home-main-footer-main {
width: 1600px; width: 1600px;
...@@ -666,7 +900,7 @@ onMounted(async () => { ...@@ -666,7 +900,7 @@ onMounted(async () => {
display: flex; display: flex;
.left { .left {
width: 389px; width: 389px;
height: 747px; height: 950px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
...@@ -679,7 +913,7 @@ onMounted(async () => { ...@@ -679,7 +913,7 @@ onMounted(async () => {
width: 8px; width: 8px;
height: 16px; height: 16px;
margin-top: 4px; margin-top: 4px;
border-radius: 2px 2px 0 0; border-radius: 0px 4px 4px 0;
background: var(--color-main-active); background: var(--color-main-active);
} }
.title { .title {
...@@ -693,16 +927,7 @@ onMounted(async () => { ...@@ -693,16 +927,7 @@ onMounted(async () => {
} }
} }
.left-box1-main { .left-box1-main {
display: grid;
grid-template-columns: repeat(2,160px);
width: 336px;
margin-top: 10px; margin-top: 10px;
margin-left: 17px;
.time-label {
height: 30px;
width: 160px;
margin-left: 8px;
}
} }
} }
} }
...@@ -716,37 +941,38 @@ onMounted(async () => { ...@@ -716,37 +941,38 @@ onMounted(async () => {
height: 60px; height: 60px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.header-left{ border-bottom: 1px solid rgba(234, 236, 238, 1);
.header-left {
display: flex; display: flex;
margin-left: 44px; margin-left: 44px;
gap: 36px; gap: 36px;
.btn-left{ .btn-left {
display: flex; display: flex;
height: 60px; height: 60px;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
.btn-text{ .btn-text {
font-size: 18px; font-size: 18px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
text-align: center; text-align: center;
} }
.btntextactive{ .btntextactive {
font-weight: 700; font-weight: 700;
color: rgba(5, 95, 194, 1); color: rgba(5, 95, 194, 1);
} }
} }
.btnleftactive{ .btnleftactive {
border-bottom: 2px solid rgba(5, 95, 194, 1); border-bottom: 2px solid rgba(5, 95, 194, 1);
} }
} }
.header-right{ .header-right {
display: flex; display: flex;
margin-right: 42px; margin-right: 42px;
gap: 12px; gap: 12px;
align-items: center; align-items: center;
.searchbox{ .searchbox {
display: flex; display: flex;
width: 300px; width: 300px;
...@@ -755,7 +981,7 @@ onMounted(async () => { ...@@ -755,7 +981,7 @@ onMounted(async () => {
border: 1px solid rgba(230, 231, 232, 1); border: 1px solid rgba(230, 231, 232, 1);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
box-sizing: border-box; box-sizing: border-box;
.search-btn{ .search-btn {
width: 16px; width: 16px;
height: 16px; height: 16px;
margin: 8px; margin: 8px;
...@@ -767,86 +993,168 @@ onMounted(async () => { ...@@ -767,86 +993,168 @@ onMounted(async () => {
width: 120px; width: 120px;
height: 32px; height: 32px;
box-sizing: border-box; box-sizing: border-box;
.paixu-btn {
display: flex;
width: 120px;
height: 32px;
box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 4px;
background: rgba(255, 255, 255, 1);
&:hover {
background: var(--color-bg-hover);
}
cursor: pointer;
.icon1 {
width: 11px;
height: 14px;
margin-top: 10px;
margin-left: 9px;
img {
width: 100%;
height: 100%;
}
}
.text {
height: 19px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
margin-top: 7px;
margin-left: 9px;
}
.icon2 {
width: 10px;
height: 5px;
margin-top: 5px;
margin-left: 13px;
img {
width: 100%;
height: 100%;
}
}
}
} }
} }
} }
.right-main { .right-main {
width: 1196px; width: 1196px;
display: flex; min-height: 790px;
flex-direction: column;
.itemlist { .itemlist {
padding-left: 25px;
padding-top: 18px;
padding-bottom: 16px;
width: 1138px; width: 1138px;
display: flex; display: flex;
margin-top: 22px;
margin-left: 18px; margin-left: 18px;
flex-direction: column; flex-direction: column;
.item-box{ border-bottom: 1px solid rgba(234, 236, 238, 1);
width: 1113px;
margin-left: 25px; .box-title {
display: flex; height: 28px;
flex-direction: column;
gap: 10px;
.box-title{
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.risktitle{ .risktitle {
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
line-height: 24px; line-height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
} }
.risktype{ .risktype {
height: 28px; height: 28px;
padding: 0 8px;
border-radius: 20px; border-radius: 20px;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 28px;
display: flex;
justify-content: center;
align-items: center;
gap: 6px;
.icon {
width: 4px;
height: 4px;
border-radius: 2px;
}
.icon1 {
background: rgba(206, 79, 81, 1);
} }
.icon2 {
background: rgba(255, 149, 77, 1);
} }
.box-source{ .icon3 {
background: var(--color-main-active);
}
}
.risk1 {
background: rgba(206, 79, 81, 0.1);
color: rgba(206, 79, 81, 1);
}
.risk2 {
background: rgba(255, 149, 77, 0.1);
color: rgba(255, 149, 77, 1);
}
.risk3 {
background: rgba(231, 243, 255, 1);
color: var(--color-main-active);
}
}
.box-source {
margin-top: 6px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
height: 24px; height: 24px;
gap: 10px; gap: 10px;
.source-pic{ .source-pic {
width: 16px; width: 16px;
height: 16px; height: 16px;
} }
.source-text{ .source-text {
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
} }
} }
.desc-box{ .desc-box {
margin-top: 9px;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
text-align: justify; text-align: justify;
} }
.tag-box{ .tag-box {
height: 28px;
margin-top: 11px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
gap: 8px; gap: 8px;
.tag {
height: 28px;
padding: 0 8px;
line-height: 28px;
border-radius: 4px;
background: rgba(231, 243, 255, 1);
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
letter-spacing: 0px;
} }
} }
.splitline{
margin: 16px auto;
background-color: rgba(234, 236, 238, 1);
height: 1px;
width: 1138px;
}
} }
} }
.right-footer { .right-footer {
display: flex; display: flex;
// height: 60px; height: 90px;
// background: orange; padding-top: 30px;
margin: 34px auto;
justify-content: space-between; justify-content: space-between;
.footer-left { .footer-left {
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
...@@ -866,4 +1174,12 @@ onMounted(async () => { ...@@ -866,4 +1174,12 @@ onMounted(async () => {
} }
} }
} }
.checkbox-all {
margin-left: 20px;
width: 260px;
}
.filter-checkbox {
width: 130px;
margin-left: 20px;
}
</style> </style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论