提交 c6f84780 authored 作者: 李智林's avatar 李智林

概览页更新

上级 6de917f9
...@@ -3,11 +3,13 @@ import request from "@/api/request.js"; ...@@ -3,11 +3,13 @@ import request from "@/api/request.js";
// 全政府-获取美国政府部门制裁数据 // 全政府-获取美国政府部门制裁数据
/** /**
* @header token * @header token
* * @param {String} params.monthNum // 月份数
*/ */
export function getAllGovernmentList() { export function getAllGovernmentList(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/rivalryIndex/governmentSanctionsData` url: `/api/rivalryIndex/governmentSanctionsData`,
params
}) })
} }
...@@ -17,7 +19,7 @@ export function getAllGovernmentList() { ...@@ -17,7 +19,7 @@ export function getAllGovernmentList() {
* @header token * @header token
* @param {Object} params * @param {Object} params
* @param {String} params.field // 领域 * @param {String} params.field // 领域
* @param {String} params.monthNum = 12 // 月份数 * @param {String} params.monthNum // 月份数
* @param {String} params.orgId // 机构ID * @param {String} params.orgId // 机构ID
* @param {String} params.sanType // 制裁手段 * @param {String} params.sanType // 制裁手段
*/ */
...@@ -66,3 +68,15 @@ export function getUSGovernmentSanctionHistory(params) { ...@@ -66,3 +68,15 @@ export function getUSGovernmentSanctionHistory(params) {
params params
}) })
} }
// 全政府-获取部门数据
/**
* @header token
*/
export function getDepartmentList() {
return request({
method: 'GET',
url: `/api/organization/summaryDepartList`
})
}
\ No newline at end of file
...@@ -3,11 +3,13 @@ import request from "@/api/request.js"; ...@@ -3,11 +3,13 @@ import request from "@/api/request.js";
// 全联盟-获取联盟列表 // 全联盟-获取联盟列表
/** /**
* @header token * @header token
* @param {Object} params
* @param {String} params.date - 日期
*/ */
export function getAllUnionList() { export function getAllUnionList(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/union/union/unionList` url: `/api/union/union/unionList/${params.date}`
}) })
} }
......
...@@ -2,18 +2,31 @@ import request from "@/api/request.js"; ...@@ -2,18 +2,31 @@ import request from "@/api/request.js";
// 全领域 // 全领域
// 全领域统计 // 全领域统计
export function getAllDomainCount() { /**
* @header token
* @param {Object} params
* @param {String} params.startDate - 开始日期
* @param {String} params.endDate - 结束日期
*/
export function getAllDomainCount(params) {
return request({ return request({
method: "GET", method: "GET",
url: `/api/rivalryIndexV2/AllDomainCount` url: `/api/rivalryIndexV2/AllDomainCount`,
params
}); });
} }
// 美对华制裁措施数量趋势 // 美对华制裁措施数量趋势
export function getDomainContainmentTrend(byYOrM = "按月统计") { /**
* @header token
* @param {Object} params
* @param {String} params.byYOrM - 按月统计或按年统计
*/
export function getDomainContainmentTrend(params) {
return request({ return request({
method: "GET", method: "GET",
url: `/api/rivalryIndexV2/DomainContainmentTrend?byYOrM=${byYOrM}` url: `/api/rivalryIndexV2/DomainContainmentTrend`,
params
}); });
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<template> <template>
<div class="content-wrapper"> <div class="content-wrapper">
<div class="btn-wrapper"> <div class="btn-wrapper" @mouseenter="stopAutoPlay" @mouseleave="startAutoPlay">
<div class="cards-mask"> <div class="cards-mask">
<div class="btn-box" :style="{ transform: `translateX(-${currentIndex * (307 + 16)}px)` }"> <div class="btn-box" :style="{ transform: `translateX(-${currentIndex * (307 + 16)}px)` }">
<div class="btn-item-outer" v-for="(item, indexx) in buttonsData" :key="indexx"> <div class="btn-item-outer" v-for="(item, indexx) in buttonsData" :key="indexx">
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
> >
<div <div
:style="{ :style="{
backgroundImage: 'url(' + `/public/icon/ZM/btn-icon2-${index % 10}.png` + ')' backgroundImage: 'url(' + `/public/icon/ZM/btn-icon2-${value.originalIndex}.png` + ')'
}" }"
class="btn-left-text" class="btn-left-text"
> >
...@@ -38,8 +38,14 @@ ...@@ -38,8 +38,14 @@
<span>美对华领域打压遏制数量趋势</span> <span>美对华领域打压遏制数量趋势</span>
</div> </div>
<div class="title-right"> <div class="title-right">
<el-select v-model="select1" placeholder="按月统计" class="custom-select"> <el-select
<el-option label="按月统计" value="" /> v-model="select1"
placeholder="按月统计"
class="custom-select"
@change="handleGetDomainContainmentTrend"
>
<el-option label="按月统计" value="按月统计" />
<el-option label="按年统计" value="按年统计" />
</el-select> </el-select>
</div> </div>
</div> </div>
...@@ -68,7 +74,7 @@ ...@@ -68,7 +74,7 @@
{{ value.date + " · " + value.type }} {{ value.date + " · " + value.type }}
</div> </div>
</div> </div>
<div class="content-title"> <div class="content-title" @click="handleClickTitle(value)">
{{ value.title }} {{ value.title }}
</div> </div>
<el-tooltip <el-tooltip
...@@ -127,14 +133,13 @@ ...@@ -127,14 +133,13 @@
<img :src="icon4" alt="" /> <img :src="icon4" alt="" />
<span>美对我领域打压遏制时间线</span> <span>美对我领域打压遏制时间线</span>
</div> </div>
<el-select v-model="selectedFieldTimeline" placeholder="全部领域" class="field-select"> <el-select v-model="selectedFieldTimeline" placeholder="全部领域" class="field-select" @change="handleGetDomainContainmentTimeline">
<el-option v-for="item in fieldOptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in fieldOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
<div class="line-main"> <div class="line-main">
<div class="nav-btn left"><img :src="leftBtn" alt="" /></div>
<div class="svg-container"> <div class="svg-container">
<svg :viewBox="`0 0 ${svgWidth} ${svgHeight}`" width="100%" height="100%"> <svg :viewBox="`0 0 ${svgWidth} ${svgHeight}`" width="100%">
<defs> <defs>
<marker <marker
id="arrow" id="arrow"
...@@ -176,7 +181,9 @@ ...@@ -176,7 +181,9 @@
<div class="item-tags"> <div class="item-tags">
<span v-for="tag in node.tags" :key="tag" :class="getTagClass(tag)">{{ tag }}</span> <span v-for="tag in node.tags" :key="tag" :class="getTagClass(tag)">{{ tag }}</span>
</div> </div>
<div class="item-title">{{ node.title }}</div> <div class="item-title">
<CommonPrompt :content="node.title" />
</div>
<el-tooltip <el-tooltip
effect="dark" effect="dark"
:content="node.content" :content="node.content"
...@@ -192,16 +199,17 @@ ...@@ -192,16 +199,17 @@
</g> </g>
</svg> </svg>
</div> </div>
<div class="nav-btn right"><img :src="rightBtn" alt="" /></div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, watch } from "vue"; import { ref, computed, onMounted, watch, inject, onUnmounted } from "vue";
import { useRouter } from "vue-router";
import setChart from "@/utils/setChart"; import setChart from "@/utils/setChart";
import getMultiLineChart from "./multiLineChart"; import getMultiLineChart from "./multiLineChart";
import CommonPrompt from "../../../../commonPrompt/index.vue";
import leftBtn from "../../assets/left-btn.png"; import leftBtn from "../../assets/left-btn.png";
import rightBtn from "../../assets/right-btn.png"; import rightBtn from "../../assets/right-btn.png";
import icon3 from "./icon/icon-3.png"; import icon3 from "./icon/icon-3.png";
...@@ -215,13 +223,56 @@ import { ...@@ -215,13 +223,56 @@ import {
getDomainContainmentRanking, getDomainContainmentRanking,
getDomainContainmentTimeline getDomainContainmentTimeline
} from "@/api/zmOverview/allDomains"; } from "@/api/zmOverview/allDomains";
import { getUSGovernmentLatestDynamic } from "@/api/allGovernment.js";
const router = useRouter();
const select1 = ref(""); const activeDate = inject("activeDate");
const select1 = ref("按月统计");
const rankType = ref("institution"); const rankType = ref("institution");
const selectedField = ref(""); const selectedField = ref("");
const selectedFieldTimeline = ref(""); const selectedFieldTimeline = ref("");
const timelineScrollX = ref(0); const timelineContainerWidth = 1700;
const timelineContainerWidth = 1601;
// 美政府部门打压遏制最新动态
const newsList = ref([]);
const getUSGovernmentLatestDynamicData = async () => {
try {
const res = await getUSGovernmentLatestDynamic();
if (res.code === 200 && res.data) {
// 将接口数据转换为 newsList 需要的格式
newsList.value = res.data.map(item => {
const dateObj = new Date(item.time);
const formattedDate = `${dateObj.getFullYear()}${dateObj.getMonth() + 1}${dateObj.getDate()}日`;
return {
id:item.id,
tags: item.industrylist || [],
date: formattedDate,
type: item.orgName || "未知机构", // 使用 orgName 作为类型信息
title: item.title,
content: item.content || item.title, // 如果 content 为空,使用 title 填充
};
});
}
} catch (error) {
console.error("获取美政府部门打压遏制最新动态失败:", error);
}
};
const handleClickTitle = (item) => {
if (!item || !item.id) return;
// 打开新标签页
const { href } = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(href, '_blank');
};
const timelineList = ref([ const timelineList = ref([
{ {
...@@ -329,13 +380,17 @@ const processTimelineData = rawData => { ...@@ -329,13 +380,17 @@ const processTimelineData = rawData => {
// 获取领域遏制时间线数据 // 获取领域遏制时间线数据
const handleGetDomainContainmentTimeline = async () => { const handleGetDomainContainmentTimeline = async () => {
try { try {
const res = await getDomainContainmentTimeline(); const params = {};
if (selectedFieldTimeline.value) {
params.domain = selectedFieldTimeline.value;
}
const res = await getDomainContainmentTimeline(params);
console.log("美对我领域打压遏制时间线", res); console.log("美对我领域打压遏制时间线", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
// 处理返回的数据结构 // 处理返回的数据结构
const processedData = processTimelineData(res.data); const processedData = processTimelineData(res.data);
timelineList.value = processedData.length > 9 ? processedData.slice(0, 9) : processedData; timelineList.value = processedData;
} }
} catch (error) { } catch (error) {
console.error("获取美对我领域打压遏制时间线失败:", error); console.error("获取美对我领域打压遏制时间线失败:", error);
...@@ -345,9 +400,9 @@ const handleGetDomainContainmentTimeline = async () => { ...@@ -345,9 +400,9 @@ const handleGetDomainContainmentTimeline = async () => {
}; };
const maxPerRow = 3; const maxPerRow = 3;
const nodeGapX = 450; const nodeGapX = 420;
const rowHeight = 215; const rowHeight = 230;
const startX = 190; const startX = 250;
const startY = 45; const startY = 45;
const axisDates = computed(() => { const axisDates = computed(() => {
...@@ -399,7 +454,7 @@ const timelineNodes = computed(() => { ...@@ -399,7 +454,7 @@ const timelineNodes = computed(() => {
contentX, contentX,
contentY, contentY,
contentWidth: 320, contentWidth: 320,
contentHeight: 140 contentHeight: 180
}; };
}); });
}); });
...@@ -475,27 +530,26 @@ const svgWidth = computed(() => { ...@@ -475,27 +530,26 @@ const svgWidth = computed(() => {
const svgHeight = computed(() => { const svgHeight = computed(() => {
const rows = Math.ceil(timelineList.value.length / maxPerRow); const rows = Math.ceil(timelineList.value.length / maxPerRow);
console.log("看下高度", rows); console.log("看下高度", rows);
return startY + rows * rowHeight; return startY + rows * rowHeight + 50;
}); });
const scrollLeft = () => { const fieldOptions = [
if (timelineScrollX.value < 0) { { value: "", label: "全部领域" },
timelineScrollX.value += nodeGapX; { value: "1", label: "人工智能" },
} { value: "2", label: "生物科技" },
}; { value: "3", label: "新一代信息技术" },
{ value: "4", label: "量子科技" },
const scrollRight = () => { { value: "5", label: "新能源" },
const maxScroll = -(timelineNodes.value.length * nodeGapX - timelineContainerWidth + startX + 100); { value: "6", label: "集成电路" },
if (timelineScrollX.value > maxScroll) { { value: "7", label: "海洋" },
timelineScrollX.value -= nodeGapX; { value: "8", label: "先进制造" },
} { value: "9", label: "新材料" },
}; { value: "10", label: "航空航天" },
const fieldOptions = ref([ { value: "11", label: "深海" },
{ label: "全部领域", value: "" }, { value: "12", label: "极地" },
{ label: "集成电路", value: "集成电路" }, { value: "13", label: "太空" },
{ label: "人工智能", value: "人工智能" }, { value: "14", label: "核" }
{ label: "量子科技", value: "量子科技" } ];
]);
// 全领域统计 // 全领域统计
const buttonsData = ref([]); const buttonsData = ref([]);
...@@ -549,18 +603,111 @@ const bgList = [ ...@@ -549,18 +603,111 @@ const bgList = [
text: "海洋", text: "海洋",
count: 25, count: 25,
background: "linear-gradient(180.00deg, rgba(153, 204, 255, 1),rgba(153, 204, 255, 0.5) 100%)" background: "linear-gradient(180.00deg, rgba(153, 204, 255, 1),rgba(153, 204, 255, 0.5) 100%)"
},
{
text: "核",
count: 25,
background: "linear-gradient(180.00deg, rgba(255, 102, 102, 1),rgba(255, 102, 102, 0.5) 100%)"
},
{
text: "太空",
count: 25,
background: "linear-gradient(180.00deg, rgba(51, 153, 255, 1),rgba(51, 153, 255, 0.5) 100%)"
},
{
text: "其他",
count: 25,
background: "linear-gradient(180.00deg, rgba(255, 187, 51, 1),rgba(255, 187, 51, 0.5) 100%)"
},
{
text: "深海",
count: 25,
background: "linear-gradient(180.00deg, rgba(117, 73, 255, 1),rgba(117, 73, 255, 0.5) 100%)"
},
{
text: "极地",
count: 25,
background: "linear-gradient(180.00deg, rgba(102, 102, 102, 1),rgba(102, 102, 102, 0.5) 100%)"
},
{
text: "新一代通信网络",
count: 25,
background: "linear-gradient(180.00deg, rgba(153, 204, 255, 1),rgba(153, 204, 255, 0.5) 100%)"
} }
]; ];
const getCalculatedDate = type => {
const now = new Date();
const endDate = new Date();
const start = new Date();
switch (type) {
case "week": // 近一个月
start.setMonth(now.getMonth() - 1);
break;
case "three_month": // 近三个月
start.setMonth(now.getMonth() - 3);
break;
case "six_month": // 近半年
start.setMonth(now.getMonth() - 6);
break;
case "year": // 近一年
start.setFullYear(now.getFullYear() - 1);
break;
default:
start.setMonth(now.getMonth() - 1); // 默认近一个月
}
const formatDate = date => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
return {
startDate: formatDate(start),
endDate: formatDate(endDate)
};
};
const handleGetAllDomainCount = async () => { const handleGetAllDomainCount = async () => {
try { try {
const res = await getAllDomainCount(); const { startDate, endDate } = getCalculatedDate(activeDate.value);
const res = await getAllDomainCount({
startDate: startDate,
endDate: endDate
});
console.log("全领域统计", res); console.log("全领域统计", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
// 按照 countNum 从大到小排序
res.data.sort((a, b) => b.countNum - a.countNum);
buttonsData.value = res.data.map((item, index) => { buttonsData.value = res.data.map((item, index) => {
const matchedBg = bgList.find(bg => bg.text === item.countName);
const background = matchedBg ? matchedBg.background : bgList[index % 10].background;
// 映射图标索引
let iconIndex = 0; // 默认
switch(item.countName) {
case '集成电路': iconIndex = 0; break;
case '人工智能': iconIndex = 1; break;
case '新一代通信网络':
case '新一代信息技术': iconIndex = 2; break;
case '量子科技': iconIndex = 3; break;
case '先进制造': iconIndex = 4; break;
case '航空航天': iconIndex = 5; break;
case '生物科技': iconIndex = 6; break;
case '新能源': iconIndex = 7; break;
case '新材料': iconIndex = 8; break;
case '海洋': iconIndex = 9; break;
default: iconIndex = 0;
}
return { return {
text: item.countName, text: item.countName,
count: item.countNum, count: item.countNum,
background: bgList[index % 10].background background: background,
originalIndex: iconIndex
}; };
}); });
const chunkSize = 2; const chunkSize = 2;
...@@ -569,6 +716,7 @@ const handleGetAllDomainCount = async () => { ...@@ -569,6 +716,7 @@ const handleGetAllDomainCount = async () => {
); );
console.log("buttonsData", buttonsData.value); console.log("buttonsData", buttonsData.value);
startAutoPlay();
} }
} catch (error) {} } catch (error) {}
}; };
...@@ -664,7 +812,9 @@ const box5Data = ref({ ...@@ -664,7 +812,9 @@ const box5Data = ref({
const handleGetDomainContainmentTrend = async () => { const handleGetDomainContainmentTrend = async () => {
try { try {
const res = await getDomainContainmentTrend(); const res = await getDomainContainmentTrend({
byYOrM: select1.value
});
console.log("美对华领域打压遏制数量趋势", res); console.log("美对华领域打压遏制数量趋势", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
...@@ -684,7 +834,7 @@ const handleGetDomainContainmentTrend = async () => { ...@@ -684,7 +834,7 @@ const handleGetDomainContainmentTrend = async () => {
// 处理领域趋势数据的方法 // 处理领域趋势数据的方法
const processDomainTrendData = rawData => { const processDomainTrendData = rawData => {
// 提取所有的月份作为标题 // 提取所有的月份作为标题
const titles = rawData.map(item => item.yearOrMonth); const titles = rawData.map(item => item.yearOrMonth).reverse();
// 收集所有不重复的领域名称 // 收集所有不重复的领域名称
const domainNamesSet = new Set(); const domainNamesSet = new Set();
...@@ -718,7 +868,7 @@ const processDomainTrendData = rawData => { ...@@ -718,7 +868,7 @@ const processDomainTrendData = rawData => {
const values = rawData.map(monthData => { const values = rawData.map(monthData => {
const domainItem = monthData.domainList.find(d => d.domainName === domainName); const domainItem = monthData.domainList.find(d => d.domainName === domainName);
return domainItem ? domainItem.domainNum : 0; return domainItem ? domainItem.domainNum : 0;
}); }).reverse(); // 数据值也需要跟随标题反转顺序
return { return {
name: domainName, name: domainName,
...@@ -733,43 +883,6 @@ const processDomainTrendData = rawData => { ...@@ -733,43 +883,6 @@ const processDomainTrendData = rawData => {
}; };
}; };
const newsList = ref([
{
tags: ["航空航天", "能源"],
title: "联邦参议院:通过2026年国防授权法案",
date: "2025年12月18日",
type: "法案",
content: "2026年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普签署成为法律,法案..."
},
{
tags: ["新材料", "生物科技"],
title: "美国FDA:针对两家中国第三方检测机构的数据完整性问题采取行动",
date: "2025年12月18日",
type: "法案",
content: "FDA因数据造假或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏...)"
},
{
tags: ["人工智能", "集成电路"],
title: "美国FCC:出台电信设备市场准入认证新规",
date: "2025年12月18日",
type: "法案",
content: "将国家安全部门审查全面嵌入设备授权程序,对实验室资质、测试标准以及供应链设置严格限制。"
},
{
tags: ["人工智能", "集成电路"],
title: "商务部工业与安全局:对实体清单的修订",
date: "2025年12月18日",
type: "法案",
content: "美国商务部工业与安全局公布对中国半导体出口管制措施新规则,将140家中国半导体公司列入..."
},
{
tags: ["集成电路"],
title: "国际贸易委员会:外国制造的半导体器件及其下游产品和组件",
date: "2025年12月18日",
type: "法案",
content: "美国国际贸易委员会(ITC)投票决定对特定半导体器件及其下游计算产品和组件(Certain ...)"
}
]);
const tagColors = [ const tagColors = [
{ {
...@@ -879,15 +992,37 @@ watch(rankType, handleGetDomainContainmentRanking); ...@@ -879,15 +992,37 @@ watch(rankType, handleGetDomainContainmentRanking);
watch(selectedField, handleGetDomainContainmentRanking); watch(selectedField, handleGetDomainContainmentRanking);
const currentIndex = ref(0); const currentIndex = ref(0);
let autoTimer = null;
const startAutoPlay = () => {
stopAutoPlay();
if (buttonsData.value.length > 5) {
autoTimer = setInterval(() => {
next();
}, 3000);
}
};
const stopAutoPlay = () => {
if (autoTimer) {
clearInterval(autoTimer);
autoTimer = null;
}
};
const next = () => { const next = () => {
if (currentIndex.value < buttonsData.value.length - 5) { if (currentIndex.value < buttonsData.value.length - 5) {
currentIndex.value++; currentIndex.value++;
} else {
currentIndex.value = 0;
} }
}; };
const prev = () => { const prev = () => {
if (currentIndex.value > 0) { if (currentIndex.value > 0) {
currentIndex.value--; currentIndex.value--;
} else {
currentIndex.value = Math.max(0, buttonsData.value.length - 5);
} }
}; };
...@@ -899,6 +1034,16 @@ onMounted(() => { ...@@ -899,6 +1034,16 @@ onMounted(() => {
handleGetAllDomainCount(); handleGetAllDomainCount();
handleGetDomainContainmentRanking(); handleGetDomainContainmentRanking();
handleGetDomainContainmentTimeline(); handleGetDomainContainmentTimeline();
getUSGovernmentLatestDynamicData();
startAutoPlay();
});
onUnmounted(() => {
stopAutoPlay();
});
watch(activeDate, () => {
handleGetAllDomainCount();
}); });
</script> </script>
...@@ -919,7 +1064,6 @@ onMounted(() => { ...@@ -919,7 +1064,6 @@ onMounted(() => {
} }
.btn-box { .btn-box {
margin-top: 16px;
width: 100%; width: 100%;
width: max-content; width: max-content;
height: 176px; height: 176px;
...@@ -1384,7 +1528,7 @@ onMounted(() => { ...@@ -1384,7 +1528,7 @@ onMounted(() => {
} }
.content-title { .content-title {
/* 容器 1576 */ cursor: pointer;
width: 689px; width: 689px;
height: 30px; height: 30px;
/* 自动布局 */ /* 自动布局 */
...@@ -1511,10 +1655,11 @@ onMounted(() => { ...@@ -1511,10 +1655,11 @@ onMounted(() => {
.svg-container { .svg-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow-x: hidden;
display: flex; overflow-y: auto;
justify-content: center; display: block;
align-items: center; padding: 0;
box-sizing: border-box;
} }
.axis-date-label { .axis-date-label {
...@@ -1543,14 +1688,18 @@ onMounted(() => { ...@@ -1543,14 +1688,18 @@ onMounted(() => {
.timeline-content-item { .timeline-content-item {
width: 100%; width: 100%;
height: 100%; height: 160px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
.item-tags { .item-tags {
width: 350px;
display: flex; display: flex;
gap: 8px; gap: 8px;
overflow: auto;
text-overflow: ellipsis;
white-space: nowrap;
.tag-item { .tag-item {
padding: 2px 8px; padding: 2px 8px;
border-radius: 4px; border-radius: 4px;
...@@ -1597,6 +1746,7 @@ onMounted(() => { ...@@ -1597,6 +1746,7 @@ onMounted(() => {
color: rgb(59, 65, 75); color: rgb(59, 65, 75);
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
line-height: 24px; line-height: 24px;
width: 100%;
} }
.item-desc { .item-desc {
...@@ -1604,11 +1754,18 @@ onMounted(() => { ...@@ -1604,11 +1754,18 @@ onMounted(() => {
font-weight: 400; font-weight: 400;
color: rgb(95, 101, 108); color: rgb(95, 101, 108);
line-height: 24px; line-height: 24px;
/* max-height: 48px; 可选:明确限制高度 */
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
display: -webkit-box; display: -webkit-box;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer; cursor: pointer;
white-space: normal;
}
.el-tooltip__trigger {
height: 48px;
} }
.item-footer { .item-footer {
......
...@@ -10,6 +10,7 @@ const getMultiLineChart = (data) => { ...@@ -10,6 +10,7 @@ const getMultiLineChart = (data) => {
const echartsSeries = series.map((item, index) => ({ const echartsSeries = series.map((item, index) => ({
name: item.name, name: item.name,
type: 'line', type: 'line',
smooth: false,
symbol: 'circle', symbol: 'circle',
symbolSize: 8, symbolSize: 8,
itemStyle: { itemStyle: {
...@@ -88,8 +89,8 @@ const getMultiLineChart = (data) => { ...@@ -88,8 +89,8 @@ const getMultiLineChart = (data) => {
{ {
type: 'value', type: 'value',
min: 0, min: 0,
max: 100, // max: 100,
interval: 20, // interval: 20,
axisLine: { axisLine: {
show: false show: false
}, },
......
...@@ -212,7 +212,7 @@ ...@@ -212,7 +212,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, computed } from "vue"; import { onMounted, ref, computed, inject } from "vue";
import setChart from "@/utils/setChart"; import setChart from "@/utils/setChart";
import getWordCloudChart from "./uitls/worldCloudChart"; import getWordCloudChart from "./uitls/worldCloudChart";
import { import {
...@@ -225,6 +225,8 @@ import { ...@@ -225,6 +225,8 @@ import {
getOrderInfo getOrderInfo
} from "@/api/zmOverview/allElement"; } from "@/api/zmOverview/allElement";
const activeDate = inject("activeDate");
// 全要素统计 // 全要素统计
const headerList = ref([]); const headerList = ref([]);
const handleGetHeaderList = async () => { const handleGetHeaderList = async () => {
......
<!--科技要闻--> <!--科技要闻-->
<template> <template>
<div class="content-wrapper"> <div class="content-wrapper">
<div class="main-content"> <div class="main-content" @mouseenter="stopAutoPlay" @mouseleave="startAutoPlay">
<div class="cards-mask"> <div class="cards-mask">
<div class="cards-container" :style="{ transform: `translateX(-${currentIndex * (307 + 16)}px)` }"> <div class="cards-container" :style="{ transform: `translateX(-${currentIndex * (307 + 16)}px)` }">
<div v-for="(card, index) in cardList" :key="index" class="government-card" @click="handleCardClick(card)"> <div v-for="(card, index) in cardList" :key="index" class="government-card" @click="handleCardClick(card)">
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
</el-select> </el-select>
<el-select v-model="deptValue" placeholder="全部部门" class="custom-select" @change="getUSChinaSanctionTrendData"> <el-select v-model="deptValue" placeholder="全部部门" class="custom-select" @change="getUSChinaSanctionTrendData">
<el-option label="全部部门" value="" /> <el-option label="全部部门" value="" />
<el-option v-for="item in departmentList" :key="item.departId" :label="item.departName" :value="item.departId" />
</el-select> </el-select>
<el-select v-model="methodValue" placeholder="全部制裁手段" class="custom-select" <el-select v-model="methodValue" placeholder="全部制裁手段" class="custom-select"
@change="getUSChinaSanctionTrendData"> @change="getUSChinaSanctionTrendData">
...@@ -59,7 +60,7 @@ ...@@ -59,7 +60,7 @@
<div class="item-right"> <div class="item-right">
<div class="dynamic-item-header"> <div class="dynamic-item-header">
<span class="item-title" @click="handleNewsClick(item)">{{ item.title }}</span> <span class="item-title" @click="handleNewsClick(item)">{{ item.title }}</span>
<span class="item-date">{{ item.date }} · {{ item.type }}</span> <span class="item-date">{{ item.date }} · {{ item.orgName }}</span>
</div> </div>
<el-tooltip effect="dark" :content="item.content" popper-class="common-prompt-popper" placement="top" <el-tooltip effect="dark" :content="item.content" popper-class="common-prompt-popper" placement="top"
:show-after="500"> :show-after="500">
...@@ -86,9 +87,10 @@ ...@@ -86,9 +87,10 @@
<div class="ranking-header"> <div class="ranking-header">
<div class="header-left"> <div class="header-left">
<div class="dept-icons"> <div class="dept-icons">
<img v-for="(dept, dIndex) in rank.depts" :key="dIndex" :src="defaultImg" alt="" class="dept-icon" /> <img v-for="(dept, dIndex) in rank.depts" :key="dIndex" :src="dept.icon || defaultImg" alt=""
class="dept-icon" />
</div> </div>
<span class="dept-names">{{ rank.depts.join(" / ") }}</span> <span class="dept-names">{{ rank.depts.map(d => d.name).join(" / ") }}</span>
</div> </div>
<div class="header-right"> <div class="header-right">
<span class="joint-count">{{ rank.count }}次联合制裁</span> <span class="joint-count">{{ rank.count }}次联合制裁</span>
...@@ -102,7 +104,8 @@ ...@@ -102,7 +104,8 @@
}}</span> }}</span>
<el-tooltip effect="dark" :content="item.title" popper-class="common-prompt-popper" placement="top" <el-tooltip effect="dark" :content="item.title" popper-class="common-prompt-popper" placement="top"
:show-after="500"> :show-after="500">
<span class="item-title">{{ item.title }}</span> <span class="item-title" :class="{ clickable: item.type === '政令' }"
@click="handleJointRankItemClick(item)">{{ item.title }}</span>
</el-tooltip> </el-tooltip>
</div> </div>
<span class="item-date">{{ item.date }}</span> <span class="item-date">{{ item.date }}</span>
...@@ -175,7 +178,7 @@ ...@@ -175,7 +178,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, computed } from "vue"; import { onMounted, ref, computed, inject, watch, onUnmounted } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import * as echarts from "echarts"; import * as echarts from "echarts";
import defaultIcon from "../../assets/defaultIcon.png"; import defaultIcon from "../../assets/defaultIcon.png";
...@@ -188,9 +191,26 @@ import icon4 from "../../assets/icon4.png"; ...@@ -188,9 +191,26 @@ import icon4 from "../../assets/icon4.png";
import timelineBg from "../../assets/timeline.png"; import timelineBg from "../../assets/timeline.png";
import defaultImg from "../../../../assets/images/default-icon2.png"; import defaultImg from "../../../../assets/images/default-icon2.png";
// 传递接口 // 传递接口
import { getAllGovernmentList, getUSChinaSanctionTrend, getUSGovernmentLatestDynamic, getUSGovernmentJointSanctionRank, getUSGovernmentSanctionHistory } from "@/api/allGovernment.js"; import { getAllGovernmentList, getUSChinaSanctionTrend, getUSGovernmentLatestDynamic, getUSGovernmentJointSanctionRank, getUSGovernmentSanctionHistory, getDepartmentList } from "@/api/allGovernment.js";
const router = useRouter(); const router = useRouter();
const activeDate = inject("activeDate");
// 根据时间范围映射月份数
const monthNum = computed(() => {
switch (activeDate.value) {
case "week":
return 1;
case "three_month":
return 3;
case "six_month":
return 6;
case "year":
return 12;
default:
return 12;
}
});
// 全政府-美政府部门对我打压遏制时间线 // 全政府-美政府部门对我打压遏制时间线
const loadingHistory = ref(false); const loadingHistory = ref(false);
...@@ -276,24 +296,19 @@ const getUSGovernmentJointSanctionRankData = async () => { ...@@ -276,24 +296,19 @@ const getUSGovernmentJointSanctionRankData = async () => {
try { try {
const res = await getUSGovernmentJointSanctionRank(); const res = await getUSGovernmentJointSanctionRank();
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
const rawData = res.data || []; rankingList.value = res.data.map(item => ({
// 按 orderId 分组 depts: (item.organizations || item.org || []).map(o => ({
const groupedData = {}; name: o.orgName,
rawData.forEach(item => { icon: o.logoUrl ? o.logoUrl.trim() : ""
if (!groupedData[item.orderId]) { })),
groupedData[item.orderId] = { count: item.jointCount,
depts: item.org ? item.org.map(o => o.orgName) : [], items: (item.sanctions || []).map(s => ({
count: item.jointCount, id: s.orderId,
items: [] type: s.typeName || '其他',
}; title: s.name,
} date: s.postDate ? s.postDate.replace(/^(\d{4})-(\d{2})-(\d{2})$/, '$1年$2月$3日') : ''
groupedData[item.orderId].items.push({ }))
type: item.sanTypeName || '其他', }));
title: item.sanName,
date: item.postDate ? item.postDate.replace(/^(\d{4})-(\d{2})-(\d{2})$/, '$1年$2月$3日') : ''
});
});
rankingList.value = Object.values(groupedData);
} }
} catch (error) { } catch (error) {
console.error("获取美政府部门联合制裁排行失败:", error); console.error("获取美政府部门联合制裁排行失败:", error);
...@@ -321,7 +336,8 @@ const getUSGovernmentLatestDynamicData = async () => { ...@@ -321,7 +336,8 @@ const getUSGovernmentLatestDynamicData = async () => {
type: item.sanTypeName || '', type: item.sanTypeName || '',
content: item.content || item.title, content: item.content || item.title,
tags: item.industrylist || [], tags: item.industrylist || [],
id: item.id id: item.id,
orgName: item.orgName || ''
})); }));
} }
} catch (error) { } catch (error) {
...@@ -343,6 +359,19 @@ const handleNewsClick = (item) => { ...@@ -343,6 +359,19 @@ const handleNewsClick = (item) => {
window.open(href, '_blank'); window.open(href, '_blank');
}; };
// 点击联合制裁项-如果是政令则跳转详情
const handleJointRankItemClick = (item) => {
if (item.type === '政令' && item.id) {
const { href } = router.resolve({
path: "/decreeLayout/overview/introduction",
query: {
id: item.id
}
});
window.open(href, '_blank');
}
};
...@@ -356,7 +385,7 @@ const getUSChinaSanctionTrendData = async () => { ...@@ -356,7 +385,7 @@ const getUSChinaSanctionTrendData = async () => {
loadingTrend.value = true; loadingTrend.value = true;
try { try {
const params = { const params = {
monthNum: 12 monthNum: monthNum.value
}; };
if (fieldValue.value) { if (fieldValue.value) {
params.field = fieldValue.value; params.field = fieldValue.value;
...@@ -371,8 +400,31 @@ const getUSChinaSanctionTrendData = async () => { ...@@ -371,8 +400,31 @@ const getUSChinaSanctionTrendData = async () => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
usChinaSanctionTrend.value = res.data; usChinaSanctionTrend.value = res.data;
// 更新图表 // 更新图表
const xAxisData = res.data.map((item) => `${item.year}-${item.month}`); let xAxisData = [];
const seriesData = res.data.map((item) => item.sanctionCount); let seriesData = [];
if (activeDate.value === "week") {
// 近一个月:按天展示
xAxisData = res.data.map((item) => {
const month = item.month.toString().padStart(2, "0");
const day = item.day.toString().padStart(2, "0");
return `${item.year}-${month}-${day}`;
});
seriesData = res.data.map((item) => item.sanctionCount);
} else {
// 近三个月、半年、一年:按月展示,需要聚合天数数据
const monthlyMap = {};
res.data.forEach((item) => {
const key = `${item.year}-${item.month.toString().padStart(2, "0")}`;
if (!monthlyMap[key]) {
monthlyMap[key] = 0;
}
monthlyMap[key] += item.sanctionCount;
});
// 排序键值确保时间轴顺序正确
xAxisData = Object.keys(monthlyMap).sort();
seriesData = xAxisData.map((key) => monthlyMap[key]);
}
initChart(xAxisData, seriesData); initChart(xAxisData, seriesData);
} }
} catch (error) { } catch (error) {
...@@ -381,6 +433,22 @@ const getUSChinaSanctionTrendData = async () => { ...@@ -381,6 +433,22 @@ const getUSChinaSanctionTrendData = async () => {
loadingTrend.value = false; loadingTrend.value = false;
} }
}; };
// 全政府-获取部门数据
const departmentList = ref([]);
const loadingDepartment = ref(false);
const getDepartmentListData = async () => {
loadingDepartment.value = true;
try {
const res = await getDepartmentList();
if (res.code === 200 && res.data) {
departmentList.value = res.data;
}
} catch (error) {
console.error("获取部门数据失败:", error);
} finally {
loadingDepartment.value = false;
}
};
...@@ -390,7 +458,11 @@ const loadingGovernment = ref(false); ...@@ -390,7 +458,11 @@ const loadingGovernment = ref(false);
const getGovernmentList = async () => { const getGovernmentList = async () => {
loadingGovernment.value = true; loadingGovernment.value = true;
try { try {
const res = await getAllGovernmentList(); const res = await getAllGovernmentList(
{
monthNum: monthNum.value
}
);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
governmentList.value = res.data; governmentList.value = res.data;
// 如果后端返回了数据,则更新 cardList // 如果后端返回了数据,则更新 cardList
...@@ -434,6 +506,7 @@ const getGovernmentList = async () => { ...@@ -434,6 +506,7 @@ const getGovernmentList = async () => {
departId: item.departId departId: item.departId
}; };
}); });
startAutoPlay();
} }
} }
} catch (error) { } catch (error) {
...@@ -518,6 +591,23 @@ const cardList = ref([ ...@@ -518,6 +591,23 @@ const cardList = ref([
]); ]);
const currentIndex = ref(0); const currentIndex = ref(0);
let autoTimer = null;
const startAutoPlay = () => {
stopAutoPlay();
if (cardList.value.length > 5) {
autoTimer = setInterval(() => {
next();
}, 3000);
}
};
const stopAutoPlay = () => {
if (autoTimer) {
clearInterval(autoTimer);
autoTimer = null;
}
};
const fieldValue = ref(""); const fieldValue = ref("");
const deptValue = ref(""); const deptValue = ref("");
const methodValue = ref(""); const methodValue = ref("");
...@@ -548,43 +638,7 @@ const methodOptions = ref([ ...@@ -548,43 +638,7 @@ const methodOptions = ref([
{ label: "行政令", value: "-2" } { label: "行政令", value: "-2" }
]); ]);
const dynamicList = ref([ const dynamicList = ref([]);
{
title: "联邦参议院:通过2026财年国防授权法案",
date: "2025年12月18日",
type: "法案",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普签署成为法律,法案...",
tags: ["航空航天", "能源"]
},
{
title: "美国FDA:针对两家中国第三方检测机构的数据完整性问题采取行动",
date: "2025年12月18日",
type: "法案",
content: "FDA因发现数据伪造或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏...",
tags: ["新材料", "生物科技"]
},
{
title: "美国FCC:出台电信设备市场准入认证新规",
date: "2025年12月18日",
type: "法案",
content: "将国家安全审查全面嵌入设备授权程序,对实验室资质、测试标准以及供应链设置严格限制。",
tags: ["人工智能", "集成电路"]
},
{
title: "商务部工业与安全局:对实体清单的修订",
date: "2025年12月18日",
type: "出口管制",
content: "美国商务部工业与安全局公布对中国半导体出口管制措施新规则,将140家中国半导体公司列入...",
tags: ["人工智能", "集成电路"]
},
{
title: "国际贸易委员会:外国制造的半导体器件及其下游产品和组件",
date: "2025年12月18日",
type: "市场准入限制",
content: "美国国际贸易委员会(ITC)投票决定对特定半导体器件及其下游计算产品和组件(Certain ...",
tags: ["集成电路"]
}
]);
const getColorName = (tag) => { const getColorName = (tag) => {
const tagColorMap = { const tagColorMap = {
...@@ -631,207 +685,9 @@ const filteredTimelineList = computed(() => { ...@@ -631,207 +685,9 @@ const filteredTimelineList = computed(() => {
}); });
}); });
const timelineList = ref([ const timelineList = ref([]);
{
name: "商务部",
count: 77,
events: [
{
date: "2025年1月24日",
content: "商务部发布《人工智能扩散框架》",
tags: ["人工智能"],
level: "red"
},
{
date: "2025年2月10日",
content: "工业与安全局出口管制指南,限制先进AI芯片及相关技术...",
tags: ["集成电路"]
},
{
date: "2025年2月15日",
content: "商务部宣布实施美国人工智能出口项目",
tags: ["人工智能"]
},
{
date: "2025年4月10日",
content: "针对中国产海运、钢、铝、铜矿产及制品加征关税",
tags: ["新材料"],
level: "yellow"
},
{
date: "2025年4月15日",
content: "工业与安全局新增实体清单,包含45家中国科技企业",
tags: ["人工智能"],
level: "red"
}
]
},
{
name: "国务院",
count: 49,
events: [
{
date: "2025年1月26日",
content: "联合声明—战略人工智能伙伴关系",
tags: ["人工智能"],
level: "green"
},
{
date: "2025年2月1日",
content: "商务部宣布实施美国人工智能出口项目商务部宣布实施美...",
tags: ["人工智能"]
},
{
date: "2025年2月13日",
content: "国务院宣布终止5项美中文化交流计划,包括政策制定者...",
tags: ["量子科技", "航空航天"],
level: "red"
},
{
date: "2025年3月8日",
content: "国务院宣布进一步调整对中国留学生的签证政策,主要针...",
tags: ["人工智能"]
},
{
date: "2025年4月19日",
content: "联合声明—战略人工智能伙伴关系",
tags: ["人工智能"],
level: "green"
}
]
},
{
name: "财政部",
count: 49,
events: [
{
date: "2025年1月28日",
content: "财政部执行税收抵免新规与供应链审查,终止电动汽车税...",
tags: ["能源"],
level: "red"
},
{
date: "2025年2月11日",
content: '将6名中国个人和10家中国实体加入"特别指定国民清单"',
tags: ["集成电路"]
},
{
date: "2025年2月27日",
content: '向EDA巨头发出"正告函",暂停处理对华出口3nm及以下...',
tags: ["集成电路"],
level: "red"
},
{
date: "2025年4月10日",
content: "财政部准备向美国9家人工智能企业投资210亿元",
tags: ["人工智能"],
level: "green"
}
]
},
{
name: "贸易代表办公室",
count: 49,
events: [
{
date: "2025年1月25日",
content: '对“中国相关船舶”进入美国港口征收“入港费”,并分...',
tags: ["能源"],
level: "yellow"
},
{
date: "2025年2月2日",
content: "对进口自中国的半导体产品加征关税",
tags: ["集成电路"]
},
{
date: "2025年2月20日",
content: '向EDA巨头发出"正告函",暂停处理对华出口3nm及以下...',
tags: ["集成电路"]
},
{
date: "2025年3月23日",
content: "财政部准备向美国9家人工智能企业投资210亿元",
tags: ["人工智能"],
level: "green"
},
{
date: "2025年4月21日",
content: "财政部拟议出台《境外投资规程》,限制对华高科技投...",
tags: ["人工智能"],
level: "yellow"
}
]
},
{
name: "商务部",
count: 77,
events: [
{
date: "2025年1月24日",
content: "商务部发布《人工智能扩散框架》",
tags: ["人工智能"],
level: "red"
},
{
date: "2025年2月10日",
content: "工业与安全局出口管制指南,限制先进AI芯片及相关技术...",
tags: ["集成电路"]
},
{
date: "2025年2月15日",
content: "商务部宣布实施美国人工智能出口项目",
tags: ["人工智能"]
},
{
date: "2025年4月10日",
content: "针对中国产海运、钢、铝、铜矿产及制品加征关税",
tags: ["新材料"],
level: "yellow"
},
{
date: "2025年4月15日",
content: "工业与安全局新增实体清单,包含45家中国科技企业",
tags: ["人工智能"],
level: "red"
}
]
}
]);
const rankingList = ref([ const rankingList = ref([]);
{
depts: ["商务部", "财政部", "国务院"],
count: 4,
items: [
{ type: "法案", title: "大而美法案", date: "2025年12月21日" },
{ type: "政令", title: "调整互惠关税范围及建立贸易与安全协议执行程序", date: "2025年12月12日" },
{ type: "政令", title: "综合对外投资国家安全法案", date: "2025年12月7日" },
{ type: "政令", title: "推动美国人工智能技术栈的出口", date: "2025年12月4日" }
]
},
{
depts: ["国务院", "食品药品监督管理局", "商务部"],
count: 2,
items: [
{ type: "法案", title: "生物安全法案", date: "2025年12月14日" },
{ type: "政令", title: "调整关税:针对中华人民共和国合成阿片类药物供应链", date: "2025年11月24日" }
]
},
{
depts: ["商务部", "联邦通信委员会"],
count: 2,
items: [
{ type: "政令", title: "保护抖音的同时保护国家安全", date: "2025年11月9日" },
{ type: "政令", title: "赢得 6G 竞赛", date: "2025年10月27日" }
]
},
{
depts: ["贸易代表办公室", "商务部"],
count: 2,
items: [{ type: "政令", title: "第301条关于中国针对海事、物流和造船业以争取主导地位的行动", date: "2025年10月24日" }]
}
]);
const chartRef = ref(null); const chartRef = ref(null);
let myChart = null; let myChart = null;
...@@ -1018,6 +874,7 @@ const initChart = (xAxisData = [], seriesData = []) => { ...@@ -1018,6 +874,7 @@ const initChart = (xAxisData = [], seriesData = []) => {
{ {
data: seriesData, data: seriesData,
type: "line", type: "line",
smooth: false,
symbol: "circle", symbol: "circle",
symbolSize: 8, symbolSize: 8,
itemStyle: { itemStyle: {
...@@ -1047,6 +904,12 @@ const initChart = (xAxisData = [], seriesData = []) => { ...@@ -1047,6 +904,12 @@ const initChart = (xAxisData = [], seriesData = []) => {
myChart.setOption(option); myChart.setOption(option);
}; };
// 监听时间范围变化,重新获取趋势数据
watch(() => activeDate.value, () => {
getUSChinaSanctionTrendData();
getGovernmentList();
});
onMounted(() => { onMounted(() => {
initChart(); initChart();
initSlider(); initSlider();
...@@ -1055,21 +918,31 @@ onMounted(() => { ...@@ -1055,21 +918,31 @@ onMounted(() => {
getUSGovernmentLatestDynamicData(); getUSGovernmentLatestDynamicData();
getUSGovernmentJointSanctionRankData(); getUSGovernmentJointSanctionRankData();
getUSGovernmentSanctionHistoryData(); getUSGovernmentSanctionHistoryData();
getDepartmentListData();
startAutoPlay();
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
myChart && myChart.resize(); myChart && myChart.resize();
sliderChart && sliderChart.resize(); sliderChart && sliderChart.resize();
}); });
}); });
onUnmounted(() => {
stopAutoPlay();
});
const next = () => { const next = () => {
if (currentIndex.value < cardList.value.length - 5) { if (currentIndex.value < cardList.value.length - 5) {
currentIndex.value++; currentIndex.value++;
} else {
currentIndex.value = 0;
} }
}; };
const prev = () => { const prev = () => {
if (currentIndex.value > 0) { if (currentIndex.value > 0) {
currentIndex.value--; currentIndex.value--;
} else {
currentIndex.value = Math.max(0, cardList.value.length - 5);
} }
}; };
</script> </script>
...@@ -1365,6 +1238,7 @@ const prev = () => { ...@@ -1365,6 +1238,7 @@ const prev = () => {
overflow-y: auto; overflow-y: auto;
.dynamic-item { .dynamic-item {
width: 100%;
display: flex; display: flex;
padding: 16px 0; padding: 16px 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
...@@ -1382,6 +1256,7 @@ const prev = () => { ...@@ -1382,6 +1256,7 @@ const prev = () => {
.item-right { .item-right {
flex: 1; flex: 1;
min-width: 0;
.dynamic-item-header { .dynamic-item-header {
display: flex; display: flex;
...@@ -1424,7 +1299,9 @@ const prev = () => { ...@@ -1424,7 +1299,9 @@ const prev = () => {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
cursor: pointer; cursor: pointer;
} }
...@@ -1596,6 +1473,13 @@ const prev = () => { ...@@ -1596,6 +1473,13 @@ const prev = () => {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
cursor: pointer; cursor: pointer;
&.clickable {
&:hover {
color: #055fc2;
text-decoration: underline;
}
}
} }
} }
......
...@@ -2,26 +2,34 @@ ...@@ -2,26 +2,34 @@
<template> <template>
<div class="content-wrapper"> <div class="content-wrapper">
<!-- 轮播栏目 --> <!-- 轮播栏目 -->
<div class="carousel-list"> <div class="carousel-list" @mouseenter="stopAutoPlay" @mouseleave="startAutoPlay">
<img src="./assets/leftbtn.png" alt class="left-btn" @click="handleSwitch('left')" /> <img src="./assets/leftbtn.png" alt class="left-btn" @click="prev" :class="{ disabled: startIndex === 0 }" />
<div class="content"> <div class="content">
<div class="carousel-item" v-for="item in showCarouselList"> <div class="carousel-container" :style="{ transform: `translateX(-${startIndex * (307 + 16)}px)` }">
<div class="item-top"> <div class="carousel-item" v-for="item in carouselList">
<div class="top-img"> <div class="item-top">
<img :src="ele" :class="{ img1: index !== 0 }" alt v-for="(ele, index) in item.imageList" /> <div class="top-img">
<img :src="ele" :class="{ img1: index !== 0 }" alt v-for="(ele, index) in item.imageList" />
</div>
<div class="top-num">{{ item.count }}</div>
</div> </div>
<div class="top-num">{{ item.count }}</div> <div class="item-title">{{ item.name }}</div>
</div>
<div class="item-title">{{ item.name }}</div>
<div class="type"> <div class="type">
<div class="type-item" :class="getClassName(ele.industryName)" v-for="ele in item.industryList"> <div class="type-item" :class="getTagClass(ele.industryName)" v-for="ele in item.industryList">
{{ ele.industryName }} {{ ele.industryName }}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<img src="./assets/rightbtn.png" alt class="right-btn" @click="handleSwitch('right')" /> <img
src="./assets/rightbtn.png"
alt
class="right-btn"
@click="next"
:class="{ disabled: startIndex >= carouselList.length - 5 }"
/>
</div> </div>
<!-- 排华联盟分布 --> <!-- 排华联盟分布 -->
...@@ -32,14 +40,14 @@ ...@@ -32,14 +40,14 @@
<div class="left-title">排华联盟分布情况</div> <div class="left-title">排华联盟分布情况</div>
</div> </div>
<div class="title-right"> <div class="title-right">
<div class="right-num" :class="{ click: currentAntiType === 'num' }">排华联盟数量</div> <!-- <div class="right-num" :class="{ click: currentAntiType === 'num' }">排华联盟数量</div> -->
<div class="right-num" :class="{ click: currentAntiType === 'active' }">排华联盟动态</div> <!-- <div class="right-num" :class="{ click: currentAntiType === 'active' }">排华联盟动态</div> -->
</div> </div>
</div> </div>
<div class="anti-content"> <div class="anti-content">
<div class="content-left"> <div class="content-left">
<div class="item" v-for="item in antiChinaNum"> <div class="item" v-for="item in countList">
<div class="item-left"> <div class="item-left">
<img :src="item.image" alt /> <img :src="item.image" alt />
<el-tooltip <el-tooltip
...@@ -70,8 +78,8 @@ ...@@ -70,8 +78,8 @@
<div class="news-content"> <div class="news-content">
<div class="item" v-for="item in newsList"> <div class="item" v-for="item in newsList">
<div class="item-title"> <div class="item-title">
<img :src="item.image" alt /> <img :src="item.image || defaultImg" alt />
<span>{{ item.title }}</span> <span @click="handleClick(item)">{{ item.title }}</span>
</div> </div>
<el-tooltip <el-tooltip
effect="dark" effect="dark"
...@@ -84,7 +92,7 @@ ...@@ -84,7 +92,7 @@
</el-tooltip> </el-tooltip>
<div class="item-bottom"> <div class="item-bottom">
<div class="bottom-left"> <div class="bottom-left">
<div class="left-item" :class="getClassName(ele.industryName)" v-for="ele in item.industryList"> <div class="left-item" :class="getTagClass(ele.industryName)" v-for="ele in item.industryList">
<span>{{ ele.industryName }}</span> <span>{{ ele.industryName }}</span>
</div> </div>
</div> </div>
...@@ -104,8 +112,9 @@ ...@@ -104,8 +112,9 @@
<div class="title-left"> <div class="title-left">
<div class="img-list"> <div class="img-list">
<img <img
:src="ele.image" :src="ele.image || defaultImg"
:class="{ img1: index !== 0 }" :class="{ img1: index !== 0 }"
@error="e => e.target.src = defaultImg"
alt alt
v-for="(ele, index) in item.countryList" v-for="(ele, index) in item.countryList"
/> />
...@@ -116,7 +125,7 @@ ...@@ -116,7 +125,7 @@
</div> </div>
<div class="item-content"> <div class="item-content">
<div class="content-list" v-for="ele in item.statementList"> <div class="content-list" v-for="ele in item.statementList">
<div class="list-left" :class="getClassName(getName(ele.industryList))"> <div class="list-left" :class="getTagClass(getName(ele.industryList))">
<span>{{ getName(ele.industryList) }}</span> <span>{{ getName(ele.industryList) }}</span>
</div> </div>
<div class="list-content">{{ ele.summary }}</div> <div class="list-content">{{ ele.summary }}</div>
...@@ -149,294 +158,216 @@ ...@@ -149,294 +158,216 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, computed } from "vue"; import { onMounted, ref, computed, inject, watch, onUnmounted } from "vue";
import router from "@/router";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { getAllUnionList, getDynamic, getPrediction, getUnionCount, getIndustry, getCountryRelation } from "@/api/allUnion.js"; import { getAllUnionList, getDynamic, getPrediction, getUnionCount, getIndustry, getCountryRelation } from "@/api/allUnion.js";
import defaultImg from "../../../../assets/images/default-icon2.png";
const carouselList = ref([ const carouselList = ref([]);
{ const countList = ref([]);
name: "芯片四方联盟1",
num: 21,
area: ["人工智能"],
imgList: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
}
]
},
{
name: "芯片四方联盟2",
num: 21,
area: ["人工智能"],
imgList: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
}
]
},
{
name: "芯片四方联盟3",
num: 21,
area: ["人工智能"],
imgList: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
}
]
},
{
name: "芯片四方联盟4",
num: 21,
area: ["人工智能"],
imgList: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
}
]
},
{
name: "芯片四方联盟5",
num: 21,
area: ["人工智能", "集成电路"],
imgList: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
}
]
},
{
name: "芯片四方联盟6",
num: 21,
area: ["人工智能"],
imgList: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png"
}
]
}
]);
const startIndex = ref(0); const startIndex = ref(0);
const activeDate = inject("activeDate", ref("week"));
const handleSwitch = flag => { // 自动轮播定时器
if (flag == "left") { let autoTimer = null;
if (startIndex.value === 0) {
startIndex.value = carouselList.value.length - 5; const startAutoPlay = () => {
} else { stopAutoPlay();
startIndex.value--; if (carouselList.value.length > 5) {
} autoTimer = setInterval(() => {
} else { next();
if (startIndex.value === carouselList.value.length - 5) { }, 3000); // 每3秒切换一次
startIndex.value = 0;
} else {
startIndex.value++;
}
} }
}; };
const getAreaList = areaList => { const stopAutoPlay = () => {
if (areaList && areaList.length > 2) { if (autoTimer) {
const array = areaList.splice(0, 2); clearInterval(autoTimer);
console.log("---areaList", array); autoTimer = null;
return array;
} else {
return areaList;
} }
}; };
const getImageList = imageList => { // 国家名称映射表,用于将接口返回的全称映射为地图支持的简称
if (imageList && imageList.length > 5) { const countryNameMap = {
const array = imageList.splice(0, 5); "Commonwealth of Australia": "Australia",
return array; Canada: "Canada",
"New Zealand": "New Zealand",
"United Kingdom of Great Britain and Northern Ireland": "United Kingdom",
"United States of America": "United States",
"Republic of India": "India",
"Brunei Darussalam": "Brunei",
"Republic of Fiji": "Fiji",
"Republic of Korea": "Korea",
"Federation of Malaysia": "Malaysia",
"Republic of the Philippines": "Philippines",
"Republic of Singapore": "Singapore",
Japan: "Japan",
"Russian Federation": "Russia",
"People's Republic of China": "China",
"Islamic Republic of Iran": "Iran",
"Syrian Arab Republic": "Syria",
"Lao People's Democratic Republic": "Laos",
"Republic of the Union of Myanmar": "Myanmar",
"Kingdom of Thailand": "Thailand",
"Republic of Indonesia": "Indonesia",
"Socialist Republic of Vietnam": "Vietnam",
"Kingdom of Cambodia": "Cambodia",
"Islamic Republic of Pakistan": "Pakistan",
"People's Republic of Bangladesh": "Bangladesh",
"Democratic Socialist Republic of Sri Lanka": "Sri Lanka",
"Federal Democratic Republic of Nepal": "Nepal",
"Kingdom of Bhutan": "Bhutan",
"French Republic": "France",
"Federal Republic of Germany": "Germany",
"Italian Republic": "Italy",
"Kingdom of Spain": "Spain",
"Kingdom of the Netherlands": "Netherlands",
"Kingdom of Belgium": "Belgium",
"Swiss Confederation": "Switzerland",
"Republic of Austria": "Austria",
"Kingdom of Sweden": "Sweden",
"Kingdom of Norway": "Norway",
"Kingdom of Denmark": "Denmark",
"Republic of Finland": "Finland",
"Hellenic Republic": "Greece",
"Republic of Turkey": "Turkey",
"State of Israel": "Israel",
"Kingdom of Saudi Arabia": "Saudi Arabia",
"Republic of South Africa": "South Africa",
"Federative Republic of Brazil": "Brazil",
"Republic of Argentina": "Argentina",
"Republic of Chile": "Chile",
"Republic of Colombia": "Colombia",
"Republic of Peru": "Peru",
"Bolivarian Republic of Venezuela": "Venezuela",
"United Mexican States": "Mexico",
"Republic of Cuba": "Cuba",
Ukraine: "Ukraine",
"Republic of Belarus": "Belarus",
"Republic of Poland": "Poland",
"Czech Republic": "Czech Republic",
Hungary: "Hungary",
Romania: "Romania",
"Republic of Bulgaria": "Bulgaria",
"Republic of Serbia": "Republic of Serbia",
"Republic of Croatia": "Croatia",
"Republic of Slovenia": "Slovenia",
"Slovak Republic": "Slovakia",
"Republic of Kazakhstan": "Kazakhstan",
"Republic of Uzbekistan": "Uzbekistan",
Turkmenistan: "Turkmenistan",
"Kyrgyz Republic": "Kyrgyzstan",
"Republic of Tajikistan": "Tajikistan",
"Republic of Azerbaijan": "Azerbaijan",
"Republic of Armenia": "Armenia",
Georgia: "Georgia",
Mongolia: "Mongolia",
"Democratic People's Republic of Korea": "North Korea",
"Republic of Iraq": "Iraq",
"State of Kuwait": "Kuwait",
"State of Qatar": "Qatar",
"Sultanate of Oman": "Oman",
"Republic of Yemen": "Yemen",
"Hashemite Kingdom of Jordan": "Jordan",
"Lebanese Republic": "Lebanon",
"Arab Republic of Egypt": "Egypt",
"State of Libya": "Libya",
"Republic of Tunisia": "Tunisia",
"People's Democratic Republic of Algeria": "Algeria",
"Kingdom of Morocco": "Morocco",
"Federal Republic of Nigeria": "Nigeria",
"Republic of Kenya": "Kenya",
"Federal Democratic Republic of Ethiopia": "Ethiopia",
"United Republic of Tanzania": "United Republic of Tanzania",
"Republic of Ghana": "Ghana",
"Republic of Côte d'Ivoire": "Ivory Coast",
"Democratic Republic of the Congo": "Democratic Republic of the Congo",
"Republic of the Congo": "Republic of the Congo",
"Republic of Zimbabwe": "Zimbabwe",
"Republic of Zambia": "Zambia",
"Republic of Angola": "Angola",
"Republic of Mozambique": "Mozambique",
"Republic of Botswana": "Botswana",
"Republic of Namibia": "Namibia",
"Republic of Ecuador": "Ecuador",
"Republic of Paraguay": "Paraguay",
"Oriental Republic of Uruguay": "Uruguay",
"Republic of Bolivia": "Bolivia",
"Republic of Panama": "Panama",
"Republic of Costa Rica": "Costa Rica",
"Republic of Nicaragua": "Nicaragua",
"Republic of Honduras": "Honduras",
"Republic of El Salvador": "El Salvador",
"Republic of Guatemala": "Guatemala",
"Dominican Republic": "Dominican Republic",
"Republic of Haiti": "Haiti",
Jamaica: "Jamaica"
};
const next = () => {
if (startIndex.value < carouselList.value.length - 5) {
startIndex.value++;
} else { } else {
return imageList; startIndex.value = 0; // 循环播放
} }
}; };
const prev = () => {
if (startIndex.value > 0) {
startIndex.value--;
}
};
// const getAreaList = areaList => {
// if (areaList && areaList.length > 2) {
// const array = areaList.splice(0, 2);
// console.log("---areaList", array);
// return array;
// } else {
// return areaList;
// }
// };
// const getImageList = imageList => {
// if (imageList && imageList.length > 5) {
// const array = imageList.splice(0, 5);
// return array;
// } else {
// return imageList;
// }
// };
//打压遏制手段分布 //打压遏制手段分布
const showCarouselList = computed(() => { const getColorName = (tag) => {
return carouselList.value.slice(startIndex.value, startIndex.value + 5); const tagColorMap = {
}); 航空航天: "blue",
const getClassName = type => { 生物科技: "blue",
let className = ""; 集成电路: "blue",
能源: "green",
新材料: "green",
人工智能: "red"
};
switch (type) { if (tagColorMap[tag]) return tagColorMap[tag];
case "人工智能":
className = "ai"; const colors = ["blue", "green", "red", "orange", "purple", "cyan"];
break; let hash = 0;
case "新材料": if (tag) {
className = "material"; for (let i = 0; i < tag.length; i++) {
break; hash = tag.charCodeAt(i) + ((hash << 5) - hash);
case "量子科技": }
className = "technology";
break;
case "生物科技":
className = "organism";
break;
case "航空航天":
className = "aerospace";
break;
case "能源":
className = "energy";
break;
case "集成电路":
className = "integrated";
break;
case "":
className = "none-class";
break;
default:
className = "other";
} }
return colors[Math.abs(hash) % colors.length];
};
return className; const getTagClass = tag => {
if (!tag) return "";
return `tag-${getColorName(tag)}`;
}; };
const currentAntiType = ref("num"); const currentAntiType = ref("num");
const antiChinaNum = ref([
{
name: "美国1111111111111111",
value: 24,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "欧盟",
value: 18,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "Japan",
value: 13,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "韩国",
value: 13,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "英国",
value: 9,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "加拿大",
value: 6,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "澳大利亚",
value: 5,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "菲律宾",
value: 3,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "新西兰",
value: 3,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
},
{
name: "印度",
value: 2,
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/us.png"
}
]);
// echarts地图的颜色区间 // echarts地图的颜色区间
const startColor = [130, 175, 224]; // rgb(130, 175, 224) const startColor = [130, 175, 224]; // rgb(130, 175, 224)
const endColor = [5, 95, 194]; // rgb(5, 95, 194) const endColor = [5, 95, 194]; // rgb(5, 95, 194)
...@@ -456,11 +387,12 @@ const getColorByValue = (value, maxValue) => { ...@@ -456,11 +387,12 @@ const getColorByValue = (value, maxValue) => {
const chartDom = ref(); const chartDom = ref();
const myChart = ref(); const myChart = ref();
function createChart() { function createChart() {
if (!countList.value) return;
// 找到最大值用于颜色计算 // 找到最大值用于颜色计算
const maxValue = Math.max(...antiChinaNum.value.map(item => item.value)); const maxValue = Math.max(...countList.value.map(item => item.value));
// 为每个数据项计算颜色 // 为每个数据项计算颜色
const processedData = antiChinaNum.value.map(item => ({ const processedData = countList.value.map(item => ({
...item, ...item,
itemStyle: { itemStyle: {
color: getColorByValue(item.value, maxValue) color: getColorByValue(item.value, maxValue)
...@@ -485,7 +417,7 @@ function createChart() { ...@@ -485,7 +417,7 @@ function createChart() {
formatter: function (params) { formatter: function (params) {
if (params.data) { if (params.data) {
// 从数据中查找对应的中文名称 // 从数据中查找对应的中文名称
const item = antiChinaNum.value.find(item => item.name === params.name); const item = countList.value.find(item => item.name === params.name);
console.log(item); console.log(item);
if (item) { if (item) {
return `${item.zhName}: ${params.data.value || 0}`; return `${item.zhName}: ${params.data.value || 0}`;
...@@ -554,123 +486,13 @@ function fetchGeoJSON() { ...@@ -554,123 +486,13 @@ function fetchGeoJSON() {
}); });
} }
const newsList = ref([ const newsList = ref([]);
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
title: "芯片四方联盟: 发布新版管制清单",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普...",
area: ["新材料", "集成电路"],
time: "2025年12月18日"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
title: "芯片四方联盟: 发布新版管制清单",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普...",
area: ["新材料", "集成电路"],
time: "2025年12月18日"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
title: "芯片四方联盟: 发布新版管制清单",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普...",
area: ["新材料", "集成电路"],
time: "2025年12月18日"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
title: "芯片四方联盟: 发布新版管制清单",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普...",
area: ["新材料", "集成电路"],
time: "2025年12月18日"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
title: "芯片四方联盟: 发布新版管制清单",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普...",
area: ["新材料", "集成电路"],
time: "2025年12月18日"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
title: "芯片四方联盟: 发布新版管制清单",
content: "2026财年国防授权法案(NDAA)已于2025年12月18日由美国总统特朗普...",
area: ["新材料", "集成电路"],
time: "2025年12月18日"
}
]);
const warningList = ref([ const warningList = ref([]);
{
countries: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
}
],
area: [
{
type: "人工智能",
content: "推出“数字基础设施增长计划框架”(DiGi Framework)",
time: "2024年11月21日"
},
{
type: "人工智能",
content: "推出“数字基础设施增长计划框架”(DiGi Framework)",
time: "2024年11月21日"
},
{
type: "人工智能",
content: "推出“数字基础设施增长计划框架”(DiGi Framework)",
time: "2024年11月21日"
}
],
num: 3
},
{
countries: [
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
},
{
img: "/src/views/ZMOverView/components/fourSuppress/components/allUnion/assets/usa.png",
name: "美国"
}
],
area: [
{
type: "人工智能",
content: "推出“数字基础设施增长计划框架”(DiGi Framework)",
time: "2024年11月21日"
}
],
num: 1
}
]);
const getContent = countries => { const getContent = countries => {
if (countries) { if (countries) {
let result = ""; // 美国 / 日本 / 韩国 / 印度 let result = "";
if (countries.length > 1) { if (countries.length > 1) {
for (let i = 0; i < countries.length; i++) { for (let i = 0; i < countries.length; i++) {
result += countries[i].name; result += countries[i].name;
...@@ -718,17 +540,6 @@ const initLeftDonut = async () => { ...@@ -718,17 +540,6 @@ const initLeftDonut = async () => {
} catch (error) { } catch (error) {
console.error("获取限制领域分布情况接口失败:", error); console.error("获取限制领域分布情况接口失败:", error);
} }
// console.log('----data', data)
// const data = [
// { name: "集成电路", value: 50 },
// { name: "人工智能", value: 46 },
// { name: "通信网络", value: 40 },
// { name: "能源", value: 32 },
// { name: "先进制造", value: 31 },
// { name: "生物科技", value: 31 },
// { name: "航空航天", value: 30 },
// { name: "新材料", value: 24 }
// ];
const option = { const option = {
tooltip: { trigger: "item", formatter: ({ name, value, percent }) => `${name}<br/>${value}${percent}%` }, tooltip: { trigger: "item", formatter: ({ name, value, percent }) => `${name}<br/>${value}${percent}%` },
...@@ -852,69 +663,6 @@ const initRightDonut = async () => { ...@@ -852,69 +663,6 @@ const initRightDonut = async () => {
} catch (error) { } catch (error) {
console.error("获取限制领域分布情况接口失败:", error); console.error("获取限制领域分布情况接口失败:", error);
} }
// console.log('----data', data)
// const data = [
// {
// name: 'Node 1',
// x: 300,
// y: 300
// },
// {
// name: 'Node 2',
// x: 800,
// y: 300
// },
// {
// name: 'Node 3',
// x: 550,
// y: 100
// },
// {
// name: 'Node 4',
// x: 550,
// y: 500
// }
// ]
// const links = [
// {
// source: 0,
// target: 1,
// symbolSize: [5, 20],
// label: {
// show: false
// },
// lineStyle: {
// width: 5,
// curveness: 0.2
// }
// },
// {
// source: 'Node 2',
// target: 'Node 1',
// label: {
// show: false
// },
// lineStyle: {
// curveness: 0.2
// }
// },
// {
// source: 'Node 1',
// target: 'Node 3'
// },
// {
// source: 'Node 2',
// target: 'Node 3'
// },
// {
// source: 'Node 2',
// target: 'Node 4'
// },
// {
// source: 'Node 1',
// target: 'Node 4'
// }
// ]
let option = { let option = {
title: { title: {
...@@ -1002,10 +750,36 @@ const colors = [ ...@@ -1002,10 +750,36 @@ const colors = [
} }
]; ];
// 获取计算后的日期
const getCalculatedDate = type => {
const now = new Date();
switch (type) {
case "week": // 近一个月
now.setMonth(now.getMonth() - 1);
break;
case "three_month": // 近三个月
now.setMonth(now.getMonth() - 3);
break;
case "six_month": // 近半年
now.setMonth(now.getMonth() - 6);
break;
case "year": // 近一年
now.setFullYear(now.getFullYear() - 1);
break;
default:
now.setMonth(now.getMonth() - 1); // 默认近一个月
}
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, "0");
const day = String(now.getDate()).padStart(2, "0");
return `${year}-${month}-${day}`;
};
// 获取联盟列表 // 获取联盟列表
const getUnionList = async () => { const getUnionList = async () => {
try { try {
const res = await getAllUnionList(); const dateParam = getCalculatedDate(activeDate.value);
const res = await getAllUnionList({ date: dateParam });
if (res && res.code === 200) { if (res && res.code === 200) {
console.log("----getUnionList", res.data); console.log("----getUnionList", res.data);
carouselList.value = res.data; carouselList.value = res.data;
...@@ -1027,6 +801,15 @@ const getDynamicList = async () => { ...@@ -1027,6 +801,15 @@ const getDynamicList = async () => {
console.error("获取联盟动态接口失败:", error); console.error("获取联盟动态接口失败:", error);
} }
}; };
const handleClick = item => {
const { href } = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(href, "_blank");
};
// 获取联盟预警 // 获取联盟预警
const getPredictionList = async () => { const getPredictionList = async () => {
...@@ -1048,12 +831,30 @@ const getUnionCountList = async () => { ...@@ -1048,12 +831,30 @@ const getUnionCountList = async () => {
if (res && res.code === 200) { if (res && res.code === 200) {
console.log("----getUnionCountList", res.data); console.log("----getUnionCountList", res.data);
// 处理一下数据 // 处理一下数据
antiChinaNum.value = res.data.map(item => { countList.value = res.data
item.value = item.count; .sort((a, b) => b.count - a.count)
item.zhName = item.name; .map(item => {
item.name = item.ename; item.value = item.count;
return item; item.zhName = item.name;
}); // 1. 尝试直接从映射表获取
let mappedName = countryNameMap[item.ename];
// 2. 如果映射表没有,尝试简单的模糊匹配
if (!mappedName && item.ename) {
let tempName = item.ename
.replace(/Republic of /i, "")
.replace(/Kingdom of /i, "")
.replace(/Federal /i, "")
.replace(/Islamic /i, "")
.replace(/State of /i, "")
.replace(/Commonwealth of /i, "")
.trim();
mappedName = tempName;
}
item.name = mappedName || item.ename;
return item;
});
} }
} catch (error) { } catch (error) {
console.error("获取联盟动态接口失败:", error); console.error("获取联盟动态接口失败:", error);
...@@ -1068,7 +869,7 @@ const getTime = time => { ...@@ -1068,7 +869,7 @@ const getTime = time => {
}; };
const getName = item => { const getName = item => {
if (item) { if (item && item.length > 0) {
return item[0].industryName; return item[0].industryName;
} else { } else {
return ""; return "";
...@@ -1083,6 +884,21 @@ onMounted(async () => { ...@@ -1083,6 +884,21 @@ onMounted(async () => {
fetchGeoJSON(); fetchGeoJSON();
initLeftDonut(); initLeftDonut();
initRightDonut(); initRightDonut();
startAutoPlay();
});
onUnmounted(() => {
stopAutoPlay();
});
watch(activeDate, async () => {
await getUnionList();
// await getDynamicList();
// await getPredictionList();
// await getUnionCountList();
// fetchGeoJSON();
// initLeftDonut();
// initRightDonut();
}); });
</script> </script>
...@@ -1090,56 +906,41 @@ onMounted(async () => { ...@@ -1090,56 +906,41 @@ onMounted(async () => {
.content-wrapper { .content-wrapper {
width: 1666px; width: 1666px;
height: 2132px; height: 2132px;
user-select: none;
// 领域样式 .tag-blue {
// 人工智能 color: rgba(9, 88, 217, 1);
.ai {
border: 1px solid rgba(255, 163, 158, 1);
background: rgba(255, 241, 240, 1);
color: rgba(245, 34, 45, 1);
}
// 新材料
.material {
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
color: rgba(19, 168, 168, 1);
}
// 量子科技
.technology {
border: 1px solid rgba(211, 173, 247, 1);
background: rgba(249, 240, 255, 1);
color: rgba(114, 46, 209, 1);
}
// 生物科技
.organism {
border: 1px solid rgba(145, 202, 255, 1);
background: rgba(230, 244, 255, 1); background: rgba(230, 244, 255, 1);
color: rgba(22, 119, 255, 1); border: 1px solid rgba(186, 224, 255, 1);
}
// 航空航天
.aerospace {
border: 1px solid rgba(173, 198, 255, 1);
background: rgba(240, 245, 255, 1);
color: rgba(22, 119, 255, 1);
} }
// 能源
.energy { .tag-green {
border: 1px solid rgba(217, 247, 190, 1);
background: rgba(246, 255, 237, 1);
color: rgba(56, 158, 13, 1); color: rgba(56, 158, 13, 1);
background: rgba(246, 255, 237, 1);
border: 1px solid rgba(217, 247, 190, 1);
} }
// 集成电路
.integrated { .tag-red {
border: 1px solid rgba(186, 224, 255, 1); color: rgba(245, 34, 45, 1);
background: rgba(230, 244, 255, 1); background: rgba(255, 241, 240, 1);
color: rgba(9, 88, 217, 1); border: 1px solid rgba(255, 163, 158, 1);
} }
// 其他
.other { .tag-orange {
border: 1px solid rgba(186, 224, 255, 1); color: rgba(250, 140, 22, 1);
background: rgba(230, 244, 255, 1); background: rgba(255, 247, 230, 1);
color: rgba(9, 88, 217, 1); border: 1px solid rgba(255, 213, 145, 1);
}
.tag-purple {
color: rgba(114, 46, 209, 1);
background: rgba(249, 240, 255, 1);
border: 1px solid rgba(211, 173, 247, 1);
}
.tag-cyan {
color: rgba(19, 194, 194, 1);
background: rgba(230, 255, 251, 1);
border: 1px solid rgba(135, 232, 222, 1);
} }
// 无类型 // 无类型
...@@ -1149,16 +950,22 @@ onMounted(async () => { ...@@ -1149,16 +950,22 @@ onMounted(async () => {
} }
.carousel-list { .carousel-list {
width: 1666px; width: 1601px;
height: 178px; height: 178px;
margin-top: 16px; margin-top: 16px;
display: flex; display: flex;
align-items: center; align-items: center;
position: relative;
.content { .content {
width: calc(100% - 48px - 16px); width: 1601px;
display: flex; overflow: hidden;
align-items: center;
justify-content: space-around; .carousel-container {
display: flex;
gap: 16px;
transition: transform 0.5s ease;
width: max-content;
}
.carousel-item { .carousel-item {
width: 307px; width: 307px;
...@@ -1226,39 +1033,54 @@ onMounted(async () => { ...@@ -1226,39 +1033,54 @@ onMounted(async () => {
width: calc(100% - 22px); width: calc(100% - 22px);
height: 25px; height: 25px;
.type-item { .type-item {
display: inline-block; display: inline-block;
border-radius: 4px; border-radius: 4px;
padding: 2px 8px; padding: 2px 8px;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
margin-left: 8px; margin-left: 8px;
margin-bottom: 8px; margin-bottom: 8px;
} box-sizing: border-box;
}
} }
} }
} }
.left-btn { .left-btn {
width: 24px; width: 24px;
height: 48px; height: 48px;
margin-right: 8px; position: absolute;
left: -33px;
z-index: 10;
cursor: pointer; cursor: pointer;
&.disabled {
opacity: 0.3;
cursor: not-allowed;
}
} }
.right-btn { .right-btn {
width: 24px; width: 24px;
height: 48px; height: 48px;
margin-left: 8px; position: absolute;
right: -33px;
z-index: 10;
cursor: pointer; cursor: pointer;
&.disabled {
opacity: 0.3;
cursor: not-allowed;
}
} }
} }
.anti-china { .anti-china {
margin-top: 16px; margin-top: 16px;
margin-left: 33px;
width: 1601px; width: 1601px;
height: 700px; height: 700px;
background: rgba(255, 255, 255, 1); border-radius: 10px;
background-color: rgba(255, 255, 255, 0.65);
box-shadow: 0 0 20px rgba(25, 69, 130, 0.1);
.anti-title { .anti-title {
width: 100%; width: 100%;
height: 48px; height: 48px;
...@@ -1267,7 +1089,8 @@ onMounted(async () => { ...@@ -1267,7 +1089,8 @@ onMounted(async () => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
.title-left { .title-left {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -1355,8 +1178,8 @@ onMounted(async () => { ...@@ -1355,8 +1178,8 @@ onMounted(async () => {
img { img {
width: 16px; width: 16px;
height: 16px; height: 12px;
margin-right: 8px; margin-right: 12px;
} }
span { span {
display: inline-block; display: inline-block;
...@@ -1402,19 +1225,15 @@ onMounted(async () => { ...@@ -1402,19 +1225,15 @@ onMounted(async () => {
.anti-news { .anti-news {
margin-top: 16px; margin-top: 16px;
margin-left: 33px;
width: 1601px; width: 1601px;
height: 700px; height: 700px;
background: rgba(255, 255, 255, 1);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.news { .news {
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: 10px; border-radius: 10px;
/* 业务系统/模块阴影 */
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 0.65); background: rgba(255, 255, 255, 0.65);
width: 793px; width: 793px;
...@@ -1425,7 +1244,8 @@ onMounted(async () => { ...@@ -1425,7 +1244,8 @@ onMounted(async () => {
height: 48px; height: 48px;
display: flex; display: flex;
align-items: center; align-items: center;
// justify-content: center; box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
img { img {
width: 22px; width: 22px;
...@@ -1449,7 +1269,7 @@ onMounted(async () => { ...@@ -1449,7 +1269,7 @@ onMounted(async () => {
.news-content { .news-content {
width: 100%; width: 100%;
height: calc(100% - 48px); height: calc(100% - 48px);
padding: 4px 28px 25px 27px; padding: 4px 28px 10px 27px;
overflow-y: auto; overflow-y: auto;
.item { .item {
...@@ -1469,7 +1289,7 @@ onMounted(async () => { ...@@ -1469,7 +1289,7 @@ onMounted(async () => {
height: 30px; height: 30px;
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer;
img { img {
width: 20px; width: 20px;
height: 20px; height: 20px;
...@@ -1526,7 +1346,7 @@ onMounted(async () => { ...@@ -1526,7 +1346,7 @@ onMounted(async () => {
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 1px 8px 1px 8px; padding: 2px 8px;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
margin-right: 8px; margin-right: 8px;
...@@ -1560,9 +1380,7 @@ onMounted(async () => { ...@@ -1560,9 +1380,7 @@ onMounted(async () => {
.warning { .warning {
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: 10px; border-radius: 10px;
/* 业务系统/模块阴影 */
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 0.65); background: rgba(255, 255, 255, 0.65);
width: 793px; width: 793px;
...@@ -1573,7 +1391,8 @@ onMounted(async () => { ...@@ -1573,7 +1391,8 @@ onMounted(async () => {
height: 48px; height: 48px;
display: flex; display: flex;
align-items: center; align-items: center;
// justify-content: center; box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
img { img {
width: 22px; width: 22px;
...@@ -1679,7 +1498,7 @@ onMounted(async () => { ...@@ -1679,7 +1498,7 @@ onMounted(async () => {
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 1px 8px 1px 8px; padding: 2px 8px;
box-sizing: border-box; box-sizing: border-box;
border-radius: 4px; border-radius: 4px;
...@@ -1730,19 +1549,15 @@ onMounted(async () => { ...@@ -1730,19 +1549,15 @@ onMounted(async () => {
.anti-area { .anti-area {
margin-top: 16px; margin-top: 16px;
margin-left: 33px;
width: 1601px; width: 1601px;
height: 500px; height: 500px;
// background: rgba(255, 255, 255, 1);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.area-left { .area-left {
width: 792px; width: 792px;
height: 500px; height: 500px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: var(---10, 10px); border-radius: var(---10, 10px);
/* 业务系统/模块阴影 */ /* 业务系统/模块阴影 */
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
...@@ -1753,7 +1568,8 @@ onMounted(async () => { ...@@ -1753,7 +1568,8 @@ onMounted(async () => {
height: 48px; height: 48px;
display: flex; display: flex;
align-items: center; align-items: center;
// justify-content: center; box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
img { img {
width: 22px; width: 22px;
...@@ -1785,7 +1601,6 @@ onMounted(async () => { ...@@ -1785,7 +1601,6 @@ onMounted(async () => {
width: 792px; width: 792px;
height: 500px; height: 500px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: var(---10, 10px); border-radius: var(---10, 10px);
/* 业务系统/模块阴影 */ /* 业务系统/模块阴影 */
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
...@@ -1796,7 +1611,8 @@ onMounted(async () => { ...@@ -1796,7 +1611,8 @@ onMounted(async () => {
height: 48px; height: 48px;
display: flex; display: flex;
align-items: center; align-items: center;
// justify-content: center; box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
img { img {
width: 17px; width: 17px;
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, computed } from "vue"; import { onMounted, ref, computed, provide } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import background from "./assets/images/backgroundBT.png"; import background from "./assets/images/backgroundBT.png";
...@@ -142,11 +142,13 @@ const handleToSearch = () => { ...@@ -142,11 +142,13 @@ const handleToSearch = () => {
}; };
const dateList = ref([ const dateList = ref([
{ name: "本周", type: "week", icon: week, activeIcon: weekActive }, { name: "近一个月", type: "week", icon: week, activeIcon: weekActive },
{ name: "本月", type: "month", icon: month, activeIcon: monthActive }, { name: "近三个月", type: "three_month", icon: month, activeIcon: monthActive },
{ name: "今年", type: "year", icon: year, activeIcon: yearActive } { name: "近半年", type: "six_month", icon: month, activeIcon: monthActive },
{ name: "近一年", type: "year", icon: year, activeIcon: yearActive }
]); ]);
const activeDate = ref("week"); const activeDate = ref("week");
provide("activeDate", activeDate);
const handleDateClick = type => { const handleDateClick = type => {
activeDate.value = type; activeDate.value = type;
}; };
...@@ -263,7 +265,7 @@ const handleDateClick = type => { ...@@ -263,7 +265,7 @@ const handleDateClick = type => {
position: relative; position: relative;
margin-top: 64px; margin-top: 64px;
.data-select { .data-select {
width: 120px; width: 140px;
height: 144px; height: 144px;
position: absolute; position: absolute;
top: 80px; top: 80px;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论