提交 d509b3b8 authored 作者: huhuiqing's avatar huhuiqing

Merge branch 'master' of http://8.140.26.4:10003/caijian/risk-monitor into dev_hhq

import request from "@/api/request.js";
// 图表解读(流式)
/**
* @param {text}
*/
export function getChartAnalysis(data) {
return request({
method: 'POST',
url: `/aiAnalysis/chart_interpretation`,
data,
})
}
\ No newline at end of file
import request from "@/api/request.js";
// 规则限制-首页统计接口
export function getStatCount() {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/statCount`
})
}
// 规则限制-查询最新动态接口
export function getLatestUpdates() {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getLatestUpdates`
})
}
// 规则限制-风险信号
export function getRiskSignal(params) {
return request({
method: 'GET',
url: `/api/commonFeature/riskSignal/${params}`
})
}
// 规则限制-查询新闻资讯
export function getNews(params) {
return request({
method: 'GET',
url: `/api/commonFeature/news/${params}`
})
}
// 规则限制-查询社交媒体
export function getRemarks(params) {
return request({
method: 'GET',
url: `/api/commonFeature/remarks/${params}`
})
}
// 规则限制-限制领域分布情况
/**
* @param {Object} params
* @param {string} params.year
* @header token
*/
export function getAreaDistribution(params) {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getAreaDistribution`,
params
})
}
// 规则限制-受限实体数量变化趋势
/**
* @param {Object} params
* @param {Integer} params.year
* @param {String} params.type
* @header token
*/
export function getEntityChangeTrend(params) {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getEntityChangeTrend`,
params
})
}
// 规则限制-规则限制政令列表查询接口
/**
* @param {Object} params
* @param {Integer} params.currentPage
* @param {Integer} params.pageSize
* @param {List<String>} params.years
* @param {List<String>} params.areas
* @param {String} params.keywords
* @param {String} params.sortField
* @param {String} params.sortOrder
* @header token
*/
export function getRuleLimitList(params) {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getRuleLimitList`,
params
})
}
// 规则限制-排华科技联盟列表接口
/**
* @param {Object} params
* @param {Integer} params.currentPage
* @param {Integer} params.pageSize
* @param {List<String>} params.years
* @param {List<String>} params.countries
* @param {List<String>} params.areas
* @param {String} params.keywords
* @param {String} params.sortField
* @param {String} params.sortOrder
* @header token
*/
export function getACTAList(params) {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getACTAList`,
params
})
}
export function getAcTAAllcountry() {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getACTAAllCountry/`
})
}
// 规则限制-规则限制基本详情
export function getSanctionOverview(params) {
return request({
method: 'GET',
url: `/api/ruleLimitInfo/getSanctionOverview/${params}`
})
}
// 实体清单-制裁概况-获取发布机构机构动态
/**
* @param {Object} data
* @param {string} data.orgId
* @header token
*/
export function getPublishOrgInfo(data) {
return request({
method: 'POST',
url: `/api/organization/relate/news`,
data,
})
}
\ No newline at end of file
......@@ -2,7 +2,6 @@
import ZMGame from "@/views/ZMGame/index.vue";
const ZMGameRoutes = [
//创新主体
{
path: "/ZMGame",
name: "ZMGame",
......
......@@ -2,10 +2,9 @@
import ZMOverview from "@/views/ZMOverView/index.vue";
const ZMOverviewRoutes = [
//创新主体
{
path: "/ZMOerView",
name: "ZMOerView",
path: "/ZMOverView",
name: "ZMOverView",
component: ZMOverview,
meta: {
title: "ZM博弈概览"
......@@ -14,4 +13,4 @@ const ZMOverviewRoutes = [
]
export default ZMOverviewRoutes
export default ZMOverviewRoutes
\ No newline at end of file
<!--科技要闻-->
<template>
<div class="content-wrapper">
全领域
</div>
</template>
<script setup>
import { onMounted, ref, computed } from "vue";
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 1666px;
height: 2132px;
}
</style>
<template>
<div class="content-wrapper">
<div class="header">
<div class="header-arrow-left">
<img src="../../assets/left-btn.png" alt="" />
</div>
<div class="header-arrow-right">
<img src="../../assets/right-btn.png" alt="" />
</div>
<div
class="header-item"
:class="{
headerItem1: index === 0,
headerItem2: index === 1,
headerItem3: index === 2,
headerItem4: index === 3,
headerItem5: index === 4
}"
v-for="(item, index) in headerList"
:key="index"
>
<div class="name">{{ item.name }}</div>
<div class="num">{{ item.value }}</div>
</div>
</div>
<div class="main">
<div class="left">
<div class="box box1">
<div class="box1-header">
<div class="icon">
<img src="./assets/images/box-header-icon1.png" alt="" />
</div>
<div class="title">{{ "最新动态" }}</div>
</div>
<div class="box1-main">
<div class="box1-item" v-for="(item, index) in box1DataList" :key="index">
<div class="box1-item-left">{{ index + 1 }}</div>
<div class="box1-item-right">
<div class="title">{{ item.title }}</div>
<div class="content">{{ item.content }}</div>
<div class="tag-box">
<div class="tag" v-for="(val, idx) in item.tagList" :key="idx">{{ val }}</div>
</div>
<div class="box1-item-right-footer">
<div class="time">{{ item.time }}</div>
<div class="area-box">
<div class="area" v-for="(vall, idxx) in item.areaList" :key="idxx">{{ vall.name }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="right">
<div class="box box2">
<div class="box2-header">
<div class="icon">
<img src="./assets/images/box-header-icon2.png" alt="" />
</div>
<div class="title">{{ "美对我要素打压情况" }}</div>
</div>
<div class="box2-main">
<div class="inner-box1">
<div class="left">
<div class="left-main">
<div
class="left-item"
:class="{ leftItemActive: box2LeftActiveIndex === index }"
v-for="(item, index) in box2DataList"
:key="index"
@click="handleClickBox2Item(index)"
>
<div class="id">{{ index + 1 }}</div>
<div class="text">{{ item.title }}</div>
</div>
</div>
<div class="left-footer">
<el-pagination
background
layout="prev, pager, next"
:total="box2Total"
:page-size="box2PageSize"
v-model:current-page="box2CurrentPage"
@current-change="handleGetBox2DataList"
/>
</div>
</div>
<div class="right">
<div class="title">{{ box2DataList[box2LeftActiveIndex].title }}</div>
<div class="tag-box">
<div
class="tag"
v-for="(item, index) in box2DataList[box2LeftActiveIndex].tagList"
:key="index"
>
{{ item }}
</div>
</div>
<div class="content">{{ box2DataList[box2LeftActiveIndex].content }}</div>
<div class="area-box">
<div
class="area"
v-for="(item, index) in box2DataList[box2LeftActiveIndex].areaList"
:key="index"
>
{{ item.name }}
</div>
</div>
<div class="footer">
{{
`${box2DataList[box2LeftActiveIndex].time} · ${box2DataList[box2LeftActiveIndex].org} · ${box2DataList[box2LeftActiveIndex].type}`
}}
</div>
</div>
</div>
<div class="inner-box2" id="box2Chart"></div>
</div>
</div>
<div class="box box3">
<div class="box3-header">
<div class="icon">
<img src="./assets/images/box-header-icon2.png" alt="" />
</div>
<div class="title">{{ "美自身要素发展情况" }}</div>
</div>
<div class="box3-main">
<div class="inner-box1">
<div class="left">
<div class="left-main">
<div
class="left-item"
:class="{ leftItemActive: box3LeftActiveIndex === index }"
v-for="(item, index) in box3DataList"
:key="index"
@click="handleClickBox3Item(index)"
>
<div class="id">{{ index + 1 }}</div>
<div class="text">{{ item.title }}</div>
</div>
</div>
<div class="left-footer">
<el-pagination
background
layout="prev, pager, next"
:total="box3Total"
:page-size="box3PageSize"
v-model:current-page="box3CurrentPage"
@current-change="handleGetBox3DataList"
/>
</div>
</div>
<div class="right">
<div class="title">{{ box3DataList[box3LeftActiveIndex].title }}</div>
<div class="tag-box">
<div
class="tag"
v-for="(item, index) in box3DataList[box3LeftActiveIndex].tagList"
:key="index"
>
{{ item }}
</div>
</div>
<div class="content">{{ box3DataList[box3LeftActiveIndex].content }}</div>
<div class="area-box">
<div
class="area"
v-for="(item, index) in box3DataList[box3LeftActiveIndex].areaList"
:key="index"
>
{{ item.name }}
</div>
</div>
<div class="footer">
{{
`${box3DataList[box3LeftActiveIndex].time} · ${box3DataList[box3LeftActiveIndex].org} · ${box3DataList[box3LeftActiveIndex].type}`
}}
</div>
</div>
</div>
<div class="inner-box2" id="box3Chart"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, computed } from "vue";
import setChart from "@/utils/setChart";
import getWordCloudChart from "./uitls/worldCloudChart";
const headerList = ref([
{
name: "科研仪器",
value: 132
},
{
name: "科研机构",
value: 104
},
{
name: "科研人才",
value: 177
},
{
name: "科研数据",
value: 60
},
{
name: "科研经费",
value: 45
}
]);
const box1DataList = ref([
{
title: '更新"中国涉军企业清单"(NS-CMIC List)',
content: "国防部新增多家中国高科技实体至清单,依据法律禁止美国人士对其进行投资。",
tagList: ["科研机构", "科研经费"],
time: "2025年12月18日",
areaList: [
{
name: "量子科技"
},
{
name: "量子科技"
}
]
},
{
title: '更新"中国涉军企业清单"(NS-CMIC List)',
content: "国防部新增多家中国高科技实体至清单,依据法律禁止美国人士对其进行投资。",
tagList: ["科研机构", "科研经费"],
time: "2025年12月18日",
areaList: [
{
name: "量子科技"
},
{
name: "量子科技"
}
]
},
{
title: '更新"中国涉军企业清单"(NS-CMIC List)',
content: "国防部新增多家中国高科技实体至清单,依据法律禁止美国人士对其进行投资。",
tagList: ["科研机构", "科研经费"],
time: "2025年12月18日",
areaList: [
{
name: "量子科技"
},
{
name: "量子科技"
}
]
},
{
title: '更新"中国涉军企业清单"(NS-CMIC List)',
content: "国防部新增多家中国高科技实体至清单,依据法律禁止美国人士对其进行投资。",
tagList: ["科研机构", "科研经费"],
time: "2025年12月18日",
areaList: [
{
name: "量子科技"
},
{
name: "量子科技"
}
]
}
]);
const box2DataList = ref([
{
title: "防止受关注国家访问美国敏感数据的规定",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定2",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定3",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定4",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定5",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
}
]);
const box2LeftActiveIndex = ref(0);
const handleClickBox2Item = index => {
box2LeftActiveIndex.value = index;
};
const box2Total = ref(25);
const box2CurrentPage = ref(1);
const box2PageSize = ref(5);
const handleGetBox2DataList = async () => {};
const box2ChartData = ref([
{
name: "限制中国获取能源技术",
value: 35
},
{
name: "加强美国在核能领域得到领导力",
value: 12
},
{
name: "关注核聚变能源研究",
value: 15
},
{
name: "发展风能",
value: 21
},
{
name: "实施能源税收延期",
value: 18
},
{
name: "限制采购中国产电池",
value: 5
},
{
name: "评估中美现代化技术",
value: 11
},
{
name: "应对中国制造2025战略",
value: 9
},
{
name: "抵制外国人才争夺",
value: 16
}
]);
const box3DataList = ref([
{
title: "防止受关注国家访问美国敏感数据的规定",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定2",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定3",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定4",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
},
{
title: "防止受关注国家访问美国敏感数据的规定5",
tagList: ["科研机构", "科研经费"],
content:
'美国司法部发布最终规则,明确禁止将"美国人"的敏感个人数据(包括基因组、生物识别、健康、地理位置及财务数据)大规模交易给中国等"受关注国家"的实体与个人。此规定旨在防止...',
areaList: [
{
name: "人工智能"
},
{
name: "生物科技"
}
],
time: "2025年12月18日",
org: "司法部",
type: "行政令"
}
]);
const box3LeftActiveIndex = ref(0);
const handleClickBox3Item = index => {
box3LeftActiveIndex.value = index;
};
const box3Total = ref(25);
const box3CurrentPage = ref(1);
const box3PageSize = ref(5);
const handleGetBox3DataList = async () => {};
const box3ChartData = ref([
{
name: "限制中国获取能源技术",
value: 35
},
{
name: "加强美国在核能领域得到领导力",
value: 12
},
{
name: "关注核聚变能源研究",
value: 15
},
{
name: "发展风能",
value: 21
},
{
name: "实施能源税收延期",
value: 18
},
{
name: "限制采购中国产电池",
value: 5
},
{
name: "评估中美现代化技术",
value: 11
},
{
name: "应对中国制造2025战略",
value: 9
},
{
name: "抵制外国人才争夺",
value: 16
}
]);
onMounted(() => {
let box2Chart = getWordCloudChart(box2ChartData.value);
setChart(box2Chart, "box2Chart");
let box3Chart = getWordCloudChart(box3ChartData.value);
setChart(box3Chart, "box3Chart");
});
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 1666px;
height: 2132px;
// background: orange;
.header {
width: 1664px;
height: 176px;
display: flex;
justify-content: center;
gap: 16px;
position: relative;
.header-arrow-left {
position: absolute;
left: 0;
top: 64px;
width: 24px;
height: 48px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.header-arrow-right {
position: absolute;
right: 0;
top: 64px;
width: 24px;
height: 48px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.header-item {
width: 307px;
height: 178px;
border-radius: 10px;
.name {
margin-top: 53px;
margin-left: 112px;
width: 174px;
height: 39px;
color: rgba(255, 255, 255, 1);
font-family: YouSheBiaoTiHei;
font-style: Regular;
font-size: 30px;
font-weight: 400;
line-height: 39px;
letter-spacing: 0px;
text-align: left;
}
.num {
margin-top: -8px;
margin-left: 112px;
width: 174px;
height: 39px;
color: rgba(255, 255, 255, 1);
font-family: YouSheBiaoTiHei;
font-style: Regular;
font-size: 30px;
font-weight: 400;
line-height: 39px;
letter-spacing: 0px;
text-align: left;
}
}
.headerItem1 {
background: url("./assets/images/bg1.png");
}
.headerItem2 {
background: url("./assets/images/bg2.png");
}
.headerItem3 {
background: url("./assets/images/bg3.png");
}
.headerItem4 {
background: url("./assets/images/bg4.png");
}
.headerItem5 {
background: url("./assets/images/bg5.png");
}
}
.main {
width: 1598px;
height: 884px;
margin: 0 auto;
margin-top: 14px;
display: flex;
justify-content: space-between;
.box {
box-sizing: border-box;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 0.65);
}
.left {
width: 472px;
.box1 {
width: 472px;
height: 884px;
overflow: hidden;
.box1-header {
height: 48px;
display: flex;
box-sizing: border-box;
border-bottom: 1px solid rgba(255, 255, 255, 1);
background: linear-gradient(180deg, rgba(231, 243, 255, 0.5), rgba(231, 243, 255, 0) 100%);
.icon {
width: 22px;
height: 18px;
margin-top: 15px;
margin-left: 16px;
img {
width: 100%;
height: 100%;
}
}
.title {
width: 89px;
height: 31px;
margin-top: 8px;
margin-left: 11px;
color: var(--color-main-active);
font-family: YouSheBiaoTiHei;
font-style: Regular;
font-size: 24px;
font-weight: 400;
line-height: 31px;
letter-spacing: 0px;
text-align: left;
}
}
.box1-main {
height: 836px;
overflow: hidden;
overflow-y: auto;
background: rgba(255, 255, 255, 0.65);
.box1-item {
width: 430px;
padding: 12px 0;
box-sizing: border-box;
border-bottom: 1px solid rgba(234, 236, 238, 1);
margin: 0 auto;
display: flex;
.box1-item-left {
width: 30px;
height: 30px;
border-radius: 50px;
background: rgba(246, 250, 255, 1);
line-height: 30px;
text-align: center;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 16px;
font-weight: 700;
line-height: 30px;
letter-spacing: 0px;
}
.box1-item-right {
width: 388px;
margin-left: 12px;
.title {
height: 30px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 16px;
font-weight: 700;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
}
.content {
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: justify;
}
.tag-box {
margin-top: 4px;
height: 28px;
display: flex;
gap: 8px;
.tag {
width: 80px;
height: 28px;
border-radius: 4px;
background: rgba(231, 243, 255, 1);
text-align: center;
line-height: 28px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
letter-spacing: 0px;
}
}
.box1-item-right-footer {
height: 30px;
margin-top: 4px;
display: flex;
justify-content: space-between;
align-items: center;
.time {
width: 124px;
height: 30px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
}
.area-box {
height: 24px;
display: flex;
gap: 8px;
justify-content: flex-end;
.area {
height: 24px;
padding: 0 8px;
line-height: 24px;
text-align: center;
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
color: rgba(19, 168, 168, 1);
}
}
}
}
}
}
}
}
.right {
width: 1110px;
.box2 {
width: 1110px;
height: 434px;
.box2-header {
height: 48px;
box-sizing: border-box;
border-bottom: 1px solid rgba(255, 255, 255, 1);
background: linear-gradient(180deg, rgba(231, 243, 255, 0.5), rgba(231, 243, 255, 0) 100%);
display: flex;
.icon {
width: 17px;
height: 16.5px;
margin-left: 19px;
margin-top: 16px;
img {
width: 100%;
height: 100%;
}
}
.title {
margin-top: 8px;
margin-left: 13px;
width: 199px;
height: 31px;
color: var(--color-main-active);
font-family: YouSheBiaoTiHei;
font-style: Regular;
font-size: 24px;
font-weight: 400;
line-height: 31px;
letter-spacing: 0px;
text-align: left;
}
}
.box2-main {
height: 386px;
background: rgba(255, 255, 255, 0.65);
display: flex;
justify-content: center;
gap: 16px;
.inner-box1 {
width: 640px;
height: 368px;
overflow: hidden;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
display: flex;
.left {
width: 320px;
border-right: 1px solid rgba(234, 236, 238, 1);
.left-main {
margin-top: 9px;
height: 270px;
.left-item {
height: 54px;
border: 1px solid transparent;
display: flex;
align-items: center;
&:hover {
background: rgba(246, 250, 255, 1);
}
cursor: pointer;
.id {
margin-left: 16px;
width: 24px;
height: 24px;
border-radius: 50px;
background: rgba(231, 243, 255, 1);
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: center;
}
.text {
width: 260px;
height: 30px;
margin-left: 12px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.leftItemActive {
box-sizing: border-box;
border: 1px solid rgba(231, 243, 255, 1);
border-radius: 4px;
background: rgba(246, 250, 255, 1);
}
}
.left-footer {
height: 80px;
display: flex;
justify-content: center;
align-items: center;
}
}
.right {
width: 320px;
.title {
width: 283px;
min-height: 24px;
max-height: 48px;
margin: 16px auto 18px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 18px;
font-weight: 700;
line-height: 24px;
letter-spacing: 0px;
text-align: justify;
}
.tag-box {
width: 283px;
margin: 0 auto;
height: 28px;
display: flex;
gap: 8px;
.tag {
height: 28px;
padding: 0 8px;
border-radius: 4px;
background: rgba(231, 243, 255, 1);
line-height: 28px;
text-align: center;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
}
}
.content {
margin: 0 auto;
margin-top: 8px;
width: 283px;
height: 150px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: justify;
}
.area-box {
width: 283px;
margin: 0 auto;
margin-top: 28px;
height: 24px;
display: flex;
justify-content: flex-start;
gap: 8px;
.area {
height: 24px;
padding: 0 8px;
line-height: 24px;
text-align: center;
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
color: rgba(19, 168, 168, 1);
}
}
.footer {
width: 283px;
margin: 0 auto;
margin-top: 8px;
height: 30px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
}
}
}
.inner-box2 {
width: 412px;
height: 368px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
}
}
}
.box3 {
margin-top: 16px;
width: 1110px;
height: 434px;
.box3-header {
height: 48px;
box-sizing: border-box;
border-bottom: 1px solid rgba(255, 255, 255, 1);
background: linear-gradient(180deg, rgba(231, 243, 255, 0.5), rgba(231, 243, 255, 0) 100%);
display: flex;
.icon {
width: 17px;
height: 16.5px;
margin-left: 19px;
margin-top: 16px;
img {
width: 100%;
height: 100%;
}
}
.title {
margin-top: 8px;
margin-left: 13px;
width: 199px;
height: 31px;
color: var(--color-main-active);
font-family: YouSheBiaoTiHei;
font-style: Regular;
font-size: 24px;
font-weight: 400;
line-height: 31px;
letter-spacing: 0px;
text-align: left;
}
}
.box3-main {
height: 386px;
background: rgba(255, 255, 255, 0.65);
display: flex;
justify-content: center;
gap: 16px;
.inner-box1 {
width: 640px;
height: 368px;
overflow: hidden;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
display: flex;
.left {
width: 320px;
border-right: 1px solid rgba(234, 236, 238, 1);
.left-main {
margin-top: 9px;
height: 270px;
.left-item {
height: 54px;
border: 1px solid transparent;
display: flex;
align-items: center;
&:hover {
background: rgba(246, 250, 255, 1);
}
cursor: pointer;
.id {
margin-left: 16px;
width: 24px;
height: 24px;
border-radius: 50px;
background: rgba(231, 243, 255, 1);
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: center;
}
.text {
width: 260px;
height: 30px;
margin-left: 12px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.leftItemActive {
box-sizing: border-box;
border: 1px solid rgba(231, 243, 255, 1);
border-radius: 4px;
background: rgba(246, 250, 255, 1);
}
}
.left-footer {
height: 80px;
display: flex;
justify-content: center;
align-items: center;
}
}
.right {
width: 320px;
.title {
width: 283px;
min-height: 24px;
max-height: 48px;
margin: 16px auto 18px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 18px;
font-weight: 700;
line-height: 24px;
letter-spacing: 0px;
text-align: justify;
}
.tag-box {
width: 283px;
margin: 0 auto;
height: 28px;
display: flex;
gap: 8px;
.tag {
height: 28px;
padding: 0 8px;
border-radius: 4px;
background: rgba(231, 243, 255, 1);
line-height: 28px;
text-align: center;
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
}
}
.content {
margin: 0 auto;
margin-top: 8px;
width: 283px;
height: 150px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: justify;
}
.area-box {
width: 283px;
margin: 0 auto;
margin-top: 28px;
height: 24px;
display: flex;
justify-content: flex-start;
gap: 8px;
.area {
height: 24px;
padding: 0 8px;
line-height: 24px;
text-align: center;
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 14px;
font-weight: 400;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid rgba(135, 232, 222, 1);
background: rgba(230, 255, 251, 1);
color: rgba(19, 168, 168, 1);
}
}
.footer {
width: 283px;
margin: 0 auto;
margin-top: 8px;
height: 30px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
}
}
}
.inner-box2 {
width: 412px;
height: 368px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
}
}
}
}
}
}
</style>
const getWordCloudChart = (data) => {
const option = {
grid: {
left: 0,
top: 0,
right: 0,
bottom: 0,
},
series: [
{
type: "wordCloud",
width: '80%',
height: '80%',
shape: "rect", //
// 其他形状你可以使用形状路径
// 或者自定义路径
// shape: 'circle' // 圆形(默认)
// shape: 'rect' // 矩形
// shape: 'roundRect' // 圆角矩形
// shape: 'triangle' // 三角形
// shape: 'diamond' // 菱形
// shape: 'pentagon' // 五边形
// shape: 'star' // 星形
// shape: 'cardioid' // 心形
gridSize: 15, // 网格大小,影响词间距。
sizeRange: [10, 30], // 定义词云中文字大小的范围
rotationRange: [0, 0],
rotationStep: 15,
drawOutOfBound: false, // 是否超出画布
// 字体
textStyle: {
// normal: {
// color: function () {
// return 'rgb(' + [
// Math.round(Math.random() * 160),
// Math.round(Math.random() * 160),
// Math.round(Math.random() * 160)
// ].join(',') + ')';
// }
// },
color: function () {
let colors = [
"rgba(189, 33, 33, 1)",
"rgba(232, 151, 21, 1)",
"rgba(220, 190, 68, 1)",
"rgba(96, 58, 186, 1)",
"rgba(32, 121, 69, 1)",
"rgba(22, 119, 255, 1)",
];
return colors[parseInt(Math.random() * colors.length)];
},
emphasis: {
shadowBlur: 5,
shadowColor: "#333",
},
},
// 设置词云数据
data: data,
},
],
}
return option
}
export default getWordCloudChart
\ No newline at end of file
<!--科技要闻-->
<template>
<div class="content-wrapper">
<div class="main-content">
<div class="cards-mask">
<div class="cards-container" :style="{ transform: `translateX(-${currentIndex * (307 + 16)}px)` }">
<div v-for="(card, index) in cardList" :key="index" class="government-card">
<div class="card-bg" :style="{ backgroundImage: `url(${card.icon || defaultIcon})` }"></div>
<div class="card-header">
<span class="card-title">{{ card.title }}</span>
<img :src="card.icon || defaultIcon" class="card-icon" alt="" />
</div>
<div class="card-body">
<div v-for="(stat, sIndex) in card.stats" :key="sIndex" class="stat-item">
<span class="stat-label">{{ stat.label }}</span>
<span class="stat-value">{{ stat.value }}</span>
</div>
</div>
</div>
</div>
</div>
<img :src="leftBtn" alt="" class="left-btn" @click="prev" :class="{ disabled: currentIndex === 0 }" />
<img
:src="rightBtn"
alt=""
class="right-btn"
@click="next"
:class="{ disabled: currentIndex >= cardList.length - 5 }"
/>
</div>
<div class="main-charts">
<div class="charts-title">
<div class="title-left">
<img :src="icon1" alt="" />
<span>美对华制裁措施数量趋势</span>
</div>
<div class="title-right">
<el-select v-model="fieldValue" placeholder="全部领域" class="custom-select">
<el-option label="全部领域" value="" />
</el-select>
<el-select v-model="deptValue" placeholder="全部部门" class="custom-select">
<el-option label="全部部门" value="" />
</el-select>
<el-select v-model="methodValue" placeholder="全部制裁手段" class="custom-select">
<el-option label="全部制裁手段" value="" />
</el-select>
</div>
</div>
<div class="charts-content">
<div ref="chartRef" class="chart-container"></div>
</div>
</div>
<div class="main-text">
<div class="text-item">
<div class="text-item-title">
<img :src="icon2" alt="" />
<span>美政府部门打压遏制最新动态</span>
</div>
<div class="text-item-content">
<div v-for="(item, index) in dynamicList" :key="index" class="dynamic-item">
<img :src="defaultImg" alt="" class="item-icon" />
<div class="item-right">
<div class="dynamic-item-header">
<span class="item-title">{{ item.title }}</span>
<span class="item-date">{{ item.date }} · {{ item.type }}</span>
</div>
<el-tooltip
effect="dark"
:content="item.content"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="dynamic-item-body">
{{ item.content }}
</div>
</el-tooltip>
<div class="dynamic-item-tags">
<span v-for="(tag, tIndex) in item.tags" :key="tIndex" class="tag" :class="getTagClass(tag)">
{{ tag }}
</span>
</div>
</div>
</div>
</div>
</div>
<div class="text-item">
<div class="text-item-title">
<img :src="icon3" alt="" />
<span>美政府部门联合制裁排行</span>
</div>
<div class="text-item-contentOther">
<div v-for="(rank, index) in rankingList" :key="index" class="ranking-card">
<div class="ranking-header">
<div class="header-left">
<div class="dept-icons">
<img
v-for="(dept, dIndex) in rank.depts"
:key="dIndex"
:src="defaultImg"
alt=""
class="dept-icon"
/>
</div>
<span class="dept-names">{{ rank.depts.join(" / ") }}</span>
</div>
<div class="header-right">
<span class="joint-count">{{ rank.count }}次联合制裁</span>
</div>
</div>
<div class="ranking-body">
<div v-for="(item, iIndex) in rank.items" :key="iIndex" class="ranking-item">
<div class="item-left">
<span class="item-type" :class="item.type === '法案' ? 'type-bill' : 'type-order'">{{
item.type
}}</span>
<el-tooltip
effect="dark"
:content="item.title"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<span class="item-title">{{ item.title }}</span>
</el-tooltip>
</div>
<span class="item-date">{{ item.date }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="main-bottom">
<div class="bottom-item">
<div class="bottom-item-title">
<img :src="icon4" alt="" />
<span>美政府部门对我打压遏制时间线</span>
</div>
<div class="bottom-item-select">
<div class="select-btn" :class="{ active: measureType === 'history' }" @click="measureType = 'history'">
历史举措
</div>
<div class="select-btn" :class="{ active: measureType === 'future' }" @click="measureType = 'future'">
未来举措
</div>
<el-select v-model="selectedField" placeholder="全部领域" class="field-select">
<el-option v-for="item in fieldOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
<div class="bottom-content">
<div class="timeline-container">
<div class="timeline-item">
<div ref="mainChartRef" :style="{ width: '100%', height: totalHeight + 'px' }"></div>
</div>
<div class="timelineBar">
<div ref="sliderChartRef" style="width: 100%; height: 100%"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, computed } from "vue";
import * as echarts from "echarts";
import defaultIcon from "../../assets/defaultIcon.png";
import leftBtn from "../../assets/left-btn.png";
import rightBtn from "../../assets/right-btn.png";
import icon1 from "../../assets/icon1.png";
import icon2 from "../../assets/icon2.png";
import icon3 from "../../assets/icon3.png";
import icon4 from "../../assets/icon4.png";
import defaultImg from "../../../../assets/images/default-icon2.png";
const cardList = ref([
{
title: "联邦参议院",
stats: [
{ label: "法案(提出)", value: "132项" },
{ label: "法案(通过)", value: "9项" }
]
},
{
title: "联邦众议院",
stats: [
{ label: "法案(提出)", value: "215项" },
{ label: "法案(通过)", value: "15项" }
]
},
{
title: "商务部",
stats: [
{ label: "232调查", value: "11次" },
{ label: "政令", value: "29项" }
]
},
{
title: "财政部",
stats: [
{ label: "232调查", value: "9次" },
{ label: "涉军企业清单", value: "3次" },
{ label: "政令", value: "15项" }
]
},
{
title: "贸易代表办公室",
stats: [
{ label: "301调查", value: "4次" },
{ label: "政令", value: "21项" }
]
},
{
title: "司法部",
stats: [
{ label: "起诉案例", value: "18宗" },
{ label: "法律制裁", value: "5项" }
]
},
{
title: "国土安全部",
stats: [
{ label: "实体清单", value: "42家" },
{ label: "限制进口", value: "12项" }
]
},
{
title: "联邦调查局",
stats: [
{ label: "技术调查", value: "33次" },
{ label: "安全审查", value: "27项" }
]
}
]);
const currentIndex = ref(0);
const fieldValue = ref("");
const deptValue = ref("");
const methodValue = ref("");
const measureType = ref("history");
const selectedField = ref("all");
const fieldOptions = ref([{ label: "全部领域", value: "all" }]);
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 getTagClass = tag => {
// 1. 定义已知标签的固定颜色映射
const tagColorMap = {
航空航天: "tag-blue",
生物科技: "tag-blue",
集成电路: "tag-blue",
能源: "tag-green",
新材料: "tag-green",
人工智能: "tag-red"
};
// 2. 如果是已知标签,直接返回对应颜色
if (tagColorMap[tag]) return tagColorMap[tag];
// 3. 如果是未知标签,使用简单的字符串哈希算法分配一个稳定的颜色
const colors = ["tag-blue", "tag-green", "tag-red"];
let hash = 0;
for (let i = 0; i < tag.length; i++) {
hash = tag.charCodeAt(i) + ((hash << 5) - hash);
}
// 取绝对值并取模,确保同一个字符串永远得到同一个颜色类
return colors[Math.abs(hash) % colors.length];
};
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);
let myChart = null;
const mainChartRef = ref(null);
const sliderChartRef = ref(null);
const totalHeight = ref(600);
let mainChart = null;
let sliderChart = null;
const parseDate = (str) => {
const match = str.match(/(\d+)(\d+)(\d+)日/);
if (match) return new Date(Number(match[1]), Number(match[2]) - 1, Number(match[3])).getTime();
return new Date().getTime();
};
const timelineAllData = computed(() => {
let all = [];
rankingList.value.forEach(rank => {
all = all.concat(rank.items);
});
dynamicList.value.forEach(item => {
all.push({ title: item.title, date: item.date, type: item.type });
});
return all.sort((a, b) => parseDate(b.date) - parseDate(a.date));
});
const updateTimeline = (startTime, endTime) => {
const filtered = timelineAllData.value.filter(item => {
const t = parseDate(item.date);
return t >= startTime && t <= endTime;
});
const itemHeight = 80;
totalHeight.value = Math.max(filtered.length * itemHeight, 552);
setTimeout(() => {
if (!mainChart) return;
mainChart.resize();
const option = {
grid: {
left: 150,
right: 50,
top: 20,
bottom: 20
},
tooltip: {
show: true,
formatter: (params) => {
const item = filtered[params.dataIndex];
return `${item.date}<br/>${item.title}`;
}
},
singleAxis: {
type: 'category',
orient: 'vertical',
data: filtered.map((_, i) => i),
top: 20,
bottom: 20,
left: 120,
width: '80%',
axisLabel: {
interval: 0,
formatter: (value, index) => {
if (!filtered[index]) return '';
return filtered[index].date;
},
align: 'right',
margin: 20,
textStyle: {
color: '#666',
fontSize: 14
}
},
axisLine: {
lineStyle: {
color: '#ccc',
width: 2
}
},
axisPointer: {
animation: true,
label: {
show: true
}
},
splitLine: { show: false }
},
series: [
{
type: 'scatter',
coordinateSystem: 'singleAxis',
data: filtered.map((_, i) => [i, 0]),
symbolSize: 14,
itemStyle: {
color: '#2f79c4',
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: (params) => {
const item = filtered[params.dataIndex];
return item.title;
},
position: 'right',
offset: [20, 0],
color: '#333',
fontSize: 16,
fontWeight: 'bold',
width: 400,
overflow: 'truncate'
}
}
]
};
mainChart.setOption(option);
}, 50);
};
const initTimeline = () => {
if (!mainChartRef.value) return;
mainChart = echarts.init(mainChartRef.value);
updateTimeline(0, Date.now() + 365 * 24 * 3600 * 1000 * 10);
};
const initSlider = () => {
if (!sliderChartRef.value) return;
sliderChart = echarts.init(sliderChartRef.value);
const dates = timelineAllData.value.map(item => parseDate(item.date));
const minDate = Math.min(...dates);
const maxDate = Math.max(...dates);
const rangeMin = minDate - 30 * 24 * 3600 * 1000;
const rangeMax = maxDate + 30 * 24 * 3600 * 1000;
const option = {
grid: {
top: 0,
bottom: 0,
left: 20,
right: 20
},
xAxis: {
type: 'time',
min: rangeMin,
max: rangeMax,
axisLabel: { show: false },
axisTick: { show: false },
axisLine: { show: false },
splitLine: { show: false }
},
yAxis: { show: false },
dataZoom: [
{
type: 'slider',
xAxisIndex: 0,
filterMode: 'weakFilter',
height: 30,
bottom: 10,
handleSize: '100%',
showDetail: true,
start: 0,
end: 100
}
],
series: [
{
type: 'scatter',
data: dates.map(d => [d, 0]),
symbolSize: 5,
itemStyle: { color: '#ccc' }
}
]
};
sliderChart.setOption(option);
sliderChart.on('dataZoom', function () {
const opt = sliderChart.getOption();
const startValue = opt.dataZoom[0].startValue;
const endValue = opt.dataZoom[0].endValue;
let startT, endT;
if (startValue != null && endValue != null) {
startT = startValue;
endT = endValue;
} else {
const range = rangeMax - rangeMin;
const startP = opt.dataZoom[0].start;
const endP = opt.dataZoom[0].end;
startT = rangeMin + range * startP / 100;
endT = rangeMin + range * endP / 100;
}
updateTimeline(startT, endT);
});
};
const initChart = () => {
if (!chartRef.value) return;
myChart = echarts.init(chartRef.value);
const option = {
tooltip: {
trigger: "axis",
backgroundColor: "rgba(255, 255, 255, 0.9)",
borderColor: "#2f79c4",
textStyle: {
color: "#666"
},
formatter: function (params) {
return `<div style="padding: 3px 6px;">
<div style="font-weight: bold; margin-bottom: 4px;">${params[0].name}</div>
<div>数量:<span style="color: #2f79c4; font-weight: bold;">${params[0].value}</span></div>
</div>`;
}
},
grid: {
top: "5%",
left: "1%",
right: "2%",
bottom: "5%",
containLabel: true
},
xAxis: {
type: "category",
boundaryGap: false,
data: [
"2024-12",
"2025-1",
"2025-2",
"2025-3",
"2025-4",
"2025-5",
"2025-6",
"2025-7",
"2025-8",
"2025-9",
"2025-10",
"2025-11"
],
axisLine: {
lineStyle: {
color: "#f0f0f0"
}
},
axisLabel: {
color: "#999",
fontSize: 12
},
axisTick: {
show: false
}
},
yAxis: {
type: "value",
min: 0,
max: 100,
interval: 20,
axisLine: {
show: false
},
axisLabel: {
color: "#999",
fontSize: 12
},
splitLine: {
lineStyle: {
type: "dashed",
color: "#f0f0f0"
}
}
},
series: [
{
data: [45, 52, 62, 62, 62, 65, 52, 75, 75, 75, 82, 92],
type: "line",
symbol: "circle",
symbolSize: 8,
itemStyle: {
color: "#fff",
borderColor: "#2f79c4",
borderWidth: 2
},
lineStyle: {
color: "#2f79c4",
width: 2
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: "rgba(47, 121, 196, 0.2)"
},
{
offset: 1,
color: "rgba(47, 121, 196, 0)"
}
])
}
}
]
};
myChart.setOption(option);
};
onMounted(() => {
initChart();
initTimeline();
initSlider();
window.addEventListener("resize", () => {
myChart && myChart.resize();
mainChart && mainChart.resize();
sliderChart && sliderChart.resize();
});
});
const next = () => {
if (currentIndex.value < cardList.value.length - 5) {
currentIndex.value++;
}
};
const prev = () => {
if (currentIndex.value > 0) {
currentIndex.value--;
}
};
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 1666px;
height: 2132px;
.main-content {
width: 100%;
position: relative;
margin-bottom: 16px;
.cards-mask {
width: 100%;
overflow: hidden; // 仅在这里隐藏超出部分,不影响外层的按钮
}
.cards-container {
display: flex;
gap: 16px;
transition: transform 0.5s ease; // 平滑过渡动画
width: max-content; // 确保容器宽度由内容撑开
}
.government-card {
width: 307px;
height: 178px;
padding: 16px 26px;
box-sizing: border-box;
border-radius: 10px;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 0 20px rgba(25, 69, 130, 0.1);
cursor: pointer;
.card-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: 358px 358px;
background-repeat: no-repeat;
background-position: center;
filter: blur(20px);
z-index: 0;
opacity: 0.8;
background-color: rgba(5, 33, 77, 0.7); // 调整为更明显的深蓝色
&::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(90deg, rgba(5, 33, 77, 1) 0%, rgba(5, 33, 77, 0) 50%, rgba(5, 33, 77, 1) 100%);
}
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 9px;
position: relative;
z-index: 1;
.card-title {
font-family: "YouSheBiaoTiHei";
font-size: 24px;
font-weight: 400;
line-height: 31px;
color: rgba(255, 255, 255, 1);
text-shadow: 0 0 30px rgba(255, 255, 255, 1);
}
.card-icon {
width: 36px; // 假设大小
height: 36px;
}
}
.card-body {
position: relative;
z-index: 1;
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
.stat-item {
display: flex;
justify-content: space-between;
align-items: center;
height: 30px;
.stat-label,
.stat-value {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 30px;
color: rgba(255, 255, 255, 0.8);
}
}
}
}
.left-btn {
width: 24px;
height: 48px;
position: absolute;
top: 50%;
left: -33px;
transform: translateY(-50%);
cursor: pointer;
z-index: 10;
transition: opacity 0.3s;
&.disabled {
opacity: 0.3;
cursor: not-allowed;
}
}
.right-btn {
width: 24px;
height: 48px;
position: absolute;
top: 50%;
right: -33px;
transform: translateY(-50%);
cursor: pointer;
z-index: 10;
transition: opacity 0.3s;
&.disabled {
opacity: 0.3;
cursor: not-allowed;
}
}
}
.main-charts {
width: 1601px;
height: 500px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.65);
box-shadow: 0 0 20px rgba(25, 69, 130, 0.1);
display: flex;
flex-direction: column;
margin-bottom: 22px;
.charts-title {
width: 100%;
height: 48px;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 17px;
padding-right: 35px;
box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
.title-left {
display: flex;
align-items: center;
img {
width: 18px;
height: 18px;
margin-right: 14px;
}
span {
font-family: YouSheBiaoTiHei;
font-size: 24px;
font-weight: 400;
line-height: 24px;
color: rgb(5, 95, 194);
}
}
.title-right {
display: flex;
height: 48px;
align-items: end;
gap: 12px;
padding-right: 17px;
.custom-select {
width: 160px;
:deep(.el-input) {
height: 32px;
.el-input__wrapper {
background-color: #fff;
box-shadow: 0 0 0 1px #dcdfe6 inset;
border-radius: 4px;
padding: 0 12px;
height: 32px;
&:hover {
box-shadow: 0 0 0 1px #c0c4cc inset;
}
&.is-focus {
box-shadow: 0 0 0 1px #409eff inset;
}
}
.el-input__inner {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
color: rgb(95, 101, 108);
height: 32px;
line-height: 24px;
&::placeholder {
color: rgb(95, 101, 108);
}
}
}
}
}
}
.charts-content {
flex: 1;
width: 100%;
padding: 20px 40px 20px 40px;
box-sizing: border-box;
.chart-container {
width: 100%;
height: 100%;
}
}
}
.main-text {
width: 1601px;
height: 700px;
display: flex;
justify-content: space-between;
margin-bottom: 16px;
.text-item {
width: 792px;
height: 700px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.65);
box-shadow: 0 0 20px rgba(25, 69, 130, 0.1);
.text-item-title {
width: 100%;
height: 48px;
display: flex;
justify-content: flex-start;
align-items: center;
padding-left: 17px;
box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
img {
width: 18px;
height: 18px;
margin-right: 14px;
}
span {
font-family: YouSheBiaoTiHei;
font-size: 24px;
font-weight: 400;
line-height: 24px;
color: rgb(5, 95, 194);
}
}
.text-item-content {
width: 100%;
height: 652px;
padding: 6px 27px 22px 27px;
box-sizing: border-box;
overflow-y: auto;
.dynamic-item {
display: flex;
padding: 16px 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&:last-child {
border-bottom: none;
}
.item-icon {
width: 24px;
height: 24px;
margin-right: 12px;
margin-top: 3px;
}
.item-right {
flex: 1;
.dynamic-item-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
.item-title {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 700;
line-height: 30px;
color: rgb(59, 65, 75);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 500px;
}
.item-date {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 30px;
color: rgb(95, 101, 108);
}
}
.dynamic-item-body {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 30px;
color: rgb(95, 101, 108);
margin-top: 0; // 紧贴标题行
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.dynamic-item-tags {
display: flex;
gap: 8px;
margin-top: 5px;
.tag {
padding: 2px 8px;
border-radius: 4px;
font-family: "Microsoft YaHei";
font-size: 14px;
font-weight: 400;
line-height: 20px;
&.tag-blue {
color: #2f79c4;
background: rgba(47, 121, 196, 0.1);
border: 1px solid rgba(47, 121, 196, 0.3);
}
&.tag-green {
color: #52c41a;
background: rgba(82, 196, 26, 0.1);
border: 1px solid rgba(82, 196, 26, 0.3);
}
&.tag-red {
color: #fa541c;
background: rgba(250, 84, 28, 0.1);
border: 1px solid rgba(250, 84, 28, 0.3);
}
}
}
}
}
}
.text-item-contentOther {
width: 100%;
height: 652px;
padding: 10px 30px 22px 27px;
box-sizing: border-box;
overflow-y: auto;
.ranking-card {
width: 100%;
border-radius: 10px;
border: 1px solid rgb(234, 236, 238);
padding: 12px 24px;
margin-bottom: 12px;
box-sizing: border-box;
&:last-child {
margin-bottom: 0;
}
.ranking-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
.header-left {
display: flex;
align-items: center;
.dept-icons {
display: flex;
margin-right: 12px;
.dept-icon {
width: 24px;
height: 24px;
margin-right: -8px; // 图标叠加效果
&:last-child {
margin-right: 0;
}
}
}
.dept-names {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 700;
line-height: 24px;
color: rgb(59, 65, 75);
}
}
.header-right {
.joint-count {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 700;
line-height: 24px;
color: rgb(59, 65, 75);
}
}
}
.ranking-body {
display: flex;
flex-direction: column;
gap: 8px;
.ranking-item {
display: flex;
justify-content: space-between;
align-items: center;
.item-left {
display: flex;
align-items: center;
flex: 1;
overflow: hidden;
.item-type {
padding: 2px 8px;
border-radius: 4px;
font-family: "Microsoft YaHei";
font-size: 14px;
font-weight: 400;
line-height: 20px;
margin-right: 13px;
&.type-bill {
color: #2f79c4;
background: rgba(47, 121, 196, 0.1);
// border: 1px solid rgba(47, 121, 196, 0.3);
}
&.type-order {
color: #2f79c4;
background: rgba(47, 121, 196, 0.1);
// border: 1px solid rgba(47, 121, 196, 0.3);
}
}
.item-title {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 30px;
color: rgb(59, 65, 75);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
}
.item-date {
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 30px;
color: rgb(95, 101, 108);
margin-left: 16px;
}
}
}
}
}
}
}
.main-bottom {
width: 100%;
height: 700px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.65);
box-shadow: 0 0 20px rgba(25, 69, 130, 0.1);
.bottom-item {
width: 100%;
height: 48px;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 17px;
padding-right: 35px;
box-sizing: border-box;
background: linear-gradient(180deg, rgba(231, 243, 255, 1) 0%, rgba(231, 243, 255, 0) 100%);
.bottom-item-title {
display: flex;
align-items: center;
img {
width: 18px;
height: 18px;
margin-right: 14px;
}
span {
font-family: YouSheBiaoTiHei;
font-size: 24px;
font-weight: 400;
line-height: 24px;
color: rgb(5, 95, 194);
}
}
.bottom-item-select {
display: flex;
height: 48px;
align-items: end;
gap: 8px;
.select-btn {
padding: 4px 16px;
border-radius: 4px;
border: 1px solid rgb(230, 231, 232);
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
line-height: 24px;
color: rgb(95, 101, 108);
cursor: pointer;
background-color: #fff;
// transition: all 0.3s;
&.active {
color: rgb(5, 95, 194);
border-color: rgb(5, 95, 194);
background-color: rgba(231, 243, 255, 1);
}
}
.field-select {
width: 160px;
:deep(.el-input) {
.el-input__wrapper {
height: 32px;
padding: 0 12px;
box-sizing: border-box;
background-color: transparent;
border-radius: 4px;
.el-input__inner {
height: 32px;
line-height: 32px;
font-family: "Microsoft YaHei";
font-size: 16px;
font-weight: 400;
color: rgb(95, 101, 108);
&::placeholder {
color: rgb(95, 101, 108);
}
}
}
}
}
}
}
.bottom-content {
width: 100%;
height: calc(100% - 48px);
padding: 14px 23px 19px 23px;
box-sizing: border-box;
.timeline-container {
width: 100%;
height: 100%;
border-radius: 4px;
padding: 8px 8px 8px 8px;
background-color: rgb(247, 248, 249);
border: 1px solid rgb(234, 236, 238);
.timeline-item {
width: 100%;
height: 552px;
overflow-y: auto;
&::-webkit-scrollbar {
display: none;
}
}
.timelineBar {
width: 100%;
height: 51px;
background-color: rgba(255, 255, 255, 1);
}
}
}
}
}
</style>
<style lang="scss">
.common-prompt-popper.el-popper {
padding: 8px 16px !important;
border-radius: 10px !important;
background-color: rgb(59, 65, 75) !important;
font-size: 16px !important;
font-weight: 400 !important;
font-family: "Microsoft YaHei" !important;
line-height: 30px !important;
color: #fff !important;
border: none !important;
.el-popper__arrow::before {
background-color: rgb(59, 65, 75) !important;
border-color: rgb(59, 65, 75) !important;
}
}
</style>
<!--科技要闻-->
<template>
<div class="content-wrapper">
全联盟
</div>
</template>
<script setup>
import { onMounted, ref, computed } from "vue";
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 1666px;
height: 2132px;
}
</style>
<!--科技要闻-->
<template>
<div class="content-wrapper">
美对华四全打压
<div class="main-nav">
<div
v-for="item in navList"
:key="item.name"
class="nav-item"
:class="{ active: activeNav === item.name }"
@click="handleNavClick(item.name)"
>
<div class="item-content">
<img v-if="activeNav === item.name" :src="right" class="active-icon" alt="" />
<span>{{ item.name }}</span>
</div>
<img v-if="activeNav === item.name" :src="background" class="active-bg" alt="" />
</div>
</div>
<!-- 切换不同的组件 -->
<AllGovernment v-if="activeNav === '全政府'" />
<AddDomain v-if="activeNav === '全领域'" />
<AllUnion v-if="activeNav === '全联盟'" />
<AllElement v-if="activeNav === '全要素'" />
</div>
</template>
<script setup>
import { onMounted, ref, computed } from "vue";
import right from "./assets/right.png";
import background from "./assets/background.png";
// 组件引入
import AllGovernment from "./components/allGovernment/index.vue";
import AddDomain from "./components/addDomain/index.vue";
import AllUnion from "./components/allUnion/index.vue";
import AllElement from "./components/allElement/index.vue";
const navList = ref([{ name: "全政府" }, { name: "全领域" }, { name: "全联盟" }, { name: "全要素" }]);
const activeNav = ref("全政府");
const handleNavClick = name => {
activeNav.value = name;
};
</script>
<style lang="scss" scoped>
.content-wrapper {
width: 100%;
height: 2203px;
// width: 1601px;
width: 1666px;
height: 2203px;
margin: 0 auto;
.main-nav {
width: 1601px;
height: 55px;
margin: 0 auto;
padding: 4px 5px;
display: flex;
align-items: center;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.65);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
box-sizing: border-box;
gap: 8px;
margin-bottom: 16px;
.nav-item {
flex: 1;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
// transition: all 0.3s;
.item-content {
display: flex;
align-items: center;
z-index: 1;
.active-icon {
width: 18px;
height: 18px;
margin-right: 8px;
}
span {
font-family: "YouSheBiaoTiHei";
font-size: 24px;
font-weight: 400;
line-height: 31px;
color: rgb(59, 65, 75);
}
}
.active-bg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
height: 60px;
z-index: 0;
}
&.active {
background-color: rgba(246, 250, 255, 1);
border: 1px solid rgba(174, 214, 255, 1);
border-radius: 10px;
span {
color: rgb(5, 95, 194);
}
}
}
}
}
</style>
......@@ -286,7 +286,7 @@ onMounted(() => {
<style lang="scss" scoped>
.content-wrapper {
width: 100%;
height: 100%;
// height: 100%;
.policy-monitoring {
font-family: Arial, sans-serif;
......
......@@ -299,9 +299,10 @@
{{ news.newsDate ? news.newsDate.slice(5) : "" }} - {{ news.newsOrg }}
</div>
</div>
<CommonPrompt :content="news.newsContent">
<div class="right-footer">{{ news.newsContent }}</div>
<!-- <CommonPrompt :content="news.newsContent">
<div class="right-footer">{{ news.newsContent }}</div>
</CommonPrompt>
</CommonPrompt> -->
</div>
</div>
</div>
......@@ -597,7 +598,7 @@
<el-checkbox class="filter-checkbox" label="全部领域"> 全部领域 </el-checkbox>
<el-checkbox
v-for="(area, index) in cateKuList"
:key="area.id"
:key="index"
:label="area.id"
class="filter-checkbox"
>
......@@ -615,7 +616,7 @@
<el-checkbox-group class="checkbox-group" v-model="activeDpList" @change="handleDpChange">
<el-checkbox
v-for="(dp, index) in dpList"
:key="dp.id"
:key="index"
:label="dp.id"
class="filter-checkbox"
>
......@@ -633,7 +634,7 @@
<el-checkbox-group class="checkbox-group" v-model="activeYyList" @change="handleYyChange">
<el-checkbox
v-for="(yy, index) in yyList"
:key="yy.id"
:key="index"
:label="yy.id"
class="filter-checkbox"
>
......@@ -652,7 +653,7 @@
<el-checkbox-group class="checkbox-group" v-model="activePubTime" @change="handlePubTimeChange">
<el-checkbox
v-for="(time, index) in pubTime"
:key="time.id"
:key="index"
:label="time.id"
class="filter-checkbox"
>
......@@ -2936,7 +2937,7 @@ onUnmounted(() => {
justify-content: flex-end;
}
.box7-main {
height: 380px;
height: 390px;
}
}
.box8 {
......
......@@ -6,7 +6,7 @@ const getDoublePieChart = (data1, data2) => {
series: [
{
type: 'pie',
radius: [45, 88],
radius: [35, 78],
// height: '100%',
left: 'center',
// width: '100%',
......@@ -32,7 +32,7 @@ const getDoublePieChart = (data1, data2) => {
},
{
type: 'pie',
radius: [90, 120],
radius: [80, 110],
height: '100%',
left: 'center',
width: '98%',
......@@ -45,18 +45,20 @@ const getDoublePieChart = (data1, data2) => {
formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
minMargin: 5,
edgeDistance: 10,
lineHeight: 24,
lineHeight: 20,
rich: {
name: {
color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei',
fontSize: 16,
fontSize: 14,
fontWeight: 'bold',
padding: [10,0,10,0]
},
time: {
fontSize: 16,
fontSize: 14,
fontFamily: 'Microsoft YaHei',
color: '#rgba(95, 101, 108, 1)'
color: '#rgba(95, 101, 108, 1)',
padding: [10,0,10,0]
}
}
},
......
......@@ -17,18 +17,20 @@ const getPieChart = (data, colorList) => {
formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
minMargin: 5,
edgeDistance: 10,
lineHeight: 25,
lineHeight: 22,
rich: {
name: {
color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei',
fontSize: 16,
fontWeight: 'bold',
padding: [10, 0, 10, 0]
},
time: {
fontSize: 16,
fontFamily: 'Microsoft YaHei',
color: '#rgba(95, 101, 108, 1)'
color: '#rgba(95, 101, 108, 1)',
padding: [10, 0, 10, 0]
}
}
......@@ -36,10 +38,10 @@ const getPieChart = (data, colorList) => {
labelLine: {
length: 15,
length2: 0,
maxSurfaceAngle: 80
maxSurfaceAngle: 88
},
labelLayout: function (params) {
const isLeft = params.labelRect.x < params.viewWidth / 2;
const isLeft = params.labelRect.x < 556 / 2;
const points = params.labelLinePoints;
// Update the end point.
points[2][0] = isLeft
......
......@@ -106,7 +106,8 @@ const getMainDataList = async () => {
params.sortOrder = value.value;
}
try {
try {
console.log('----params getMainDataList', params)
const res = await getCoopRestrictionList(params);
if (res && res.code === 200) {
mainDataList.value = (res.data.content || []).map(item => ({
......
......@@ -16,7 +16,7 @@ const getPieChart = (data) => {
formatter: '{name|{b}}\n{time|{d}%}',
minMargin: 5,
edgeDistance: 10,
lineHeight: 24,
lineHeight: 22,
rich: {
name: {
color: 'rgba(59, 65, 75, 1)',
......@@ -27,7 +27,7 @@ const getPieChart = (data) => {
time: {
fontSize: 16,
fontFamily: 'Microsoft YaHei',
color: '#rgba(95, 101, 108, 1)'
color: '#rgba(95, 101, 108, 1)',
}
}
},
......
......@@ -161,26 +161,26 @@
@click="handlePerClick(item)"
>
<img :src="item.imageUrl" alt />
<div class="person-info">
<el-tooltip
effect="dark"
:content="item.name"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="name">{{ item.name }}</div>
</el-tooltip>
<el-tooltip
effect="dark"
:content="item.position"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="title1">{{ item.position }}</div>
</el-tooltip>
<el-tooltip
effect="dark"
:content="item.name"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="name">{{ item.name }}</div>
</el-tooltip>
<el-tooltip
effect="dark"
:content="item.position"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="title1">{{ item.position }}</div>
</el-tooltip>
</div>
</div>
</div>
......@@ -916,10 +916,10 @@ onMounted(() => {
flex-shrink: 0;
}
.person-info {
width: calc(100% - 48px - 8px);
width: calc(100% - 48px - 8px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* 防止文本换行 */
white-space: nowrap; /* 防止文本换行 */
.name {
font-size: 16px;
font-weight: 700;
......
......@@ -78,7 +78,7 @@
</template>
<script setup>
import { ref, defineProps, defineEmits, computed, watch } from "vue";
import { ref, computed, watch } from "vue";
import router from "@/router";
import { Close } from "@element-plus/icons-vue";
import defaultIcon from "@/assets/icons/default-icon1.png";
......
......@@ -620,13 +620,13 @@
<div class="item-right-header">
<div class="tag" :class="{tag1: item.SORTCODE === '337', tag2: item.SORTCODE === '301', tag3: item.SORTCODE === '232' }">{{ item.SORTCODE }}</div>
<div class="title">{{ item.SEARCHNAME }}</div>
<div class="status">
<div class="status" v-if="item.CASESTATUS">
<div class="status-icon"></div>
<div class="status-text">{{ item.CASESTATUS }}</div>
</div>
</div>
<div class="item-right-content">
{{ item.content }}
<div class="item-right-content" v-if="item.CONTENT">
{{ item.CONTENT }}
</div>
<div class="item-right-footer">
<div class="area-box" v-for="(val, idx) in item.searchArea" :key="idx">
......@@ -1600,9 +1600,6 @@ const handleGetSurveyList = async () => {
if (res.code === 200 && res.data) {
totalDiscussNum.value = res.data.totalElements;
surveyInfoList.value = res.data.content;
surveyInfoList.value.forEach(item => {
item.SORTIMAGEURL = `http://${item.SORTIMAGEURL}`
})
} else {
surveyInfoList.value = [];
}
......@@ -3179,7 +3176,8 @@ onMounted(async () => {
border-bottom: 1px solid rgba(230, 231, 232, 1);
// height: 780px;
.item {
height: 154px;
// height: 154px;
min-height: 94px;
display: flex;
cursor: pointer;
&:hover {
......@@ -3199,17 +3197,21 @@ onMounted(async () => {
}
.item-center {
width: 30px;
height: 154px;
// height: 154px;
.icon {
width: 30px;
height: 30px;
border-radius: 15px;
background: orange;
img{
width: 100%;
height: 100%;
}
}
.line {
margin-left: 14px;
width: 2px;
height: 124px;
min-height: 64px;
max-height: 124px;
border-radius: 1.5px;
background: rgba(234, 236, 238, 1);
}
......@@ -3261,13 +3263,17 @@ onMounted(async () => {
line-height: 26px;
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status {
margin-left: 9px;
display: flex;
width: 76px;
height: 24px;
justify-content: space-between;
justify-content: flex-end;
gap: 5px;
align-items: center;
.status-icon {
width: 4px;
......@@ -3323,16 +3329,23 @@ onMounted(async () => {
}
.flag-box {
display: flex;
position: relative;
.flag {
width: 24px;
height: 24px;
border-radius: 12px;
border: 2px solid #fff;
overflow: hidden;
position: absolute;
img{
width: 100%;
height: 100%;
}
}
:nth-child(1) {
left: 18px;
z-index: 99;
}
}
}
}
......
......@@ -54,24 +54,19 @@ const getBarChart = (nameList, valueList) => {
},
barWidth: 20,
markPoint: {
symbol: 'circle',
symbolSize: 0,
// symbol: 'circle',
// symbolSize: 0,
data: (function () {
const data = [];
nameList.forEach((item, index) => {
data.push({
name: 'icon',
// value: '',
xAxis: index,
yAxis: valueList[index],
symbol: `image://${item.img}`,
symbolSize: [20, 20],
symbolOffset: [0, 10],
// itemStyle: {
// borderRadius: 10, // 设置为圆形
// borderColor: '#fff',
// borderWidth: 2
// }
symbolCircle: 10
});
});
return data;
......
......@@ -2,128 +2,108 @@
<div class="ask-page">
<div class="left">
<div class="left-title">
<img src="./assets/icon01.png" alt="" />
<img src="./assets/icon01.png" alt />
<div class="tit">新闻资讯</div>
<div class="more" @click="handleToMoreNews">更多 +</div>
</div>
<div class="left-main">
<div v-for="item in leftList.slice(0, 5)" :key="item.id" class="main-item" @click="handleToNewsDetail(item)">
<img :src="item.image || defaultNews" alt="" @error="e => (e.target.src = defaultNews)" />
<div v-for="item in leftList" :key="item.newsId" class="main-item">
<img :src="item.newsImage" alt />
<div class="item-content">
<div class="title">
<CommonPrompt :content="item.title">
{{ item.title }}
</CommonPrompt>
</div>
<div class="content">
<CommonPrompt :content="item.content">
{{ item.content }}
</CommonPrompt>
</div>
<div class="time">{{ item.time }}</div>
<div class="title">{{item.newsTitle}}</div>
<el-tooltip
effect="dark"
:content="item.newsContent"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<div class="content">{{item.newsContent}}</div>
</el-tooltip>
<div class="time">{{item.newsDate}}</div>
</div>
</div>
</div>
</div>
<div class="right">
<div class="right-title">
<img src="./assets/icon02.png" alt="" />
<img src="./assets/icon02.png" alt />
<div class="tit">社交媒体</div>
</div>
<div class="right-main">
<div
v-for="(item, index) in rightList.slice(0, 3)"
:key="item.id"
class="social-item"
@click="handleToSocialDetail(item)"
>
<img :src="item.image || defaultAvatar" alt="" @error="e => (e.target.src = defaultAvatar)" />
<div class="social-item-main" :style="{ backgroundImage: `url(${socialConfig[index].bg})` }">
<div class="cl1">{{ item.name }}</div>
<div class="cl2">{{ item.content }}</div>
<div class="cl3">{{ item.time }}</div>
<div class="trump" v-for="item in rightList">
<img :src="item.personImage" alt />
<div class="trump-main">
<div class="cl1">{{ item.personName }}</div>
<div class="cl2">{{ item.remarks }}</div>
<div class="cl3">{{ item.time }}&nbsp; 发布于{{ item.orgName }}</div>
</div>
</div>
<!-- <div class="mask">
<img src="./assets/title02.png" alt />
<div class="mask-main">
<div class="cl1">{{ rightList[1].name }}</div>
<div class="cl2">{{ rightList[1].content }}</div>
<div class="cl3">{{ rightList[1].time }}</div>
</div>
</div>
<div class="malaby">
<img src="./assets/title03.png" alt />
<div class="malaby-main">
<div class="cl1">{{ rightList[2].name }}</div>
<div class="cl2">{{ rightList[2].content }}</div>
<div class="cl3">{{ rightList[2].time }}</div>
</div>
</div> -->
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import router from "@/router";
import { getRuleRestrictionNews, getRuleRestrictionSocialMedia } from "@/api/ruleRestriction/ruleRestriction";
import CommonPrompt from "../../commonPrompt/index.vue";
import { ref, onBeforeMount } from "vue";
import router from "@/router"
import image01 from './assets/image01.png'
import image02 from './assets/image02.png'
import image03 from './assets/image03.png'
import image04 from './assets/image04.png'
import image05 from './assets/image05.png'
import defaultNews from "../../assets/images/default-icon-news.png";
import defaultAvatar from "../../assets/images/default-icon1.png";
import title01 from "./assets/title01.png";
import title02 from "./assets/title02.png";
import title03 from "./assets/title03.png";
import title01bg from "./assets/title01bg.png";
import title02bg from "./assets/title02bg.png";
import title03bg from "./assets/title03bg.png";
import title01 from './assets/title01.png'
import title02 from './assets/title02.png'
import title03 from './assets/title03.png'
import { getNews, getRemarks } from '@/api/ruleRestriction/index.js'
const leftList = ref([]);
const rightList = ref([]);
const socialConfig = [
{ icon: title01, bg: title01bg },
{ icon: title02, bg: title02bg },
{ icon: title03, bg: title03bg }
];
// 规则限制-查询新闻资讯接口
const getRuleRestrictionNewsData = async () => {
try {
const res = await getRuleRestrictionNews({ moduleId: "0108" });
if (res && res.code === 200) {
leftList.value = (res.data || []).map(item => ({
id: item.newsId,
title: item.newsTitle,
content: item.newsContent,
time: `${item.newsDate}${item.newsOrg ? " · " + item.newsOrg : ""}`,
image: item.newsImage
}));
}
} catch (error) {
console.error("获取规则限制新闻资讯数据失败:", error);
}
};
const getNewsList = async () => {
try {
const res = await getNews('0108');
// console.log('----res', res)
if (res && res.code === 200) {
// console.log('----getNewsList', res.data)
leftList.value = res.data
}
} catch (error) {
console.error("获取新闻资讯接口失败:", error);
}
}
// 规则限制-查询社交媒体接口
const getRuleRestrictionSocialData = async () => {
try {
const res = await getRuleRestrictionSocialMedia({ moduleId: "0108" });
if (res && res.code === 200) {
rightList.value = (res.data || []).map(item => {
const date = new Date(item.time);
const y = date.getFullYear();
const m = (date.getMonth() + 1).toString().padStart(2, "0");
const d = date.getDate().toString().padStart(2, "0");
const hh = date.getHours().toString().padStart(2, "0");
const mm = date.getMinutes().toString().padStart(2, "0");
const formattedTime = `${y}-${m}-${d} ${hh}:${mm} · 发布于${item.orgName}`;
return {
id: item.personId,
name: item.personName,
content: item.remarks,
time: formattedTime,
image: item.personImage
};
});
}
} catch (error) {
console.error("获取规则限制社交媒体数据失败:", error);
}
};
const getRemarksList = async () => {
try {
const res = await getRemarks('0108');
// console.log('----res', res)
if (res && res.code === 200) {
// console.log('----getRemarksList', res.data)
rightList.value = res.data
}
} catch (error) {
console.error("获取社交媒体接口失败:", error);
}
}
// 查看更多新闻资讯
const handleToMoreNews = () => {
const route = router.resolve("/newsBrief");
window.open(route.href, "_blank");
};
// 查看新闻资讯详情
const handleToNewsDetail = item => {
const route = router.resolve({
......@@ -146,10 +126,12 @@ const handleToSocialDetail = item => {
window.open(route.href, "_blank");
};
onMounted(() => {
getRuleRestrictionNewsData();
getRuleRestrictionSocialData();
});
onBeforeMount(async () => {
await getNewsList()
await getRemarksList()
})
</script>
<style scoped lang="scss">
......@@ -211,6 +193,8 @@ onMounted(() => {
width: 792px;
height: 402px;
padding: 20px 22px 21px 21px;
overflow-y: auto;
overflow-x: hidden;
.main-item {
width: 749px;
height: 64px;
......@@ -231,28 +215,23 @@ onMounted(() => {
height: 50px;
position: relative;
.title {
width: 480px;
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.content {
width: 100%;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
cursor: pointer;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
white-space: nowrap; /* 防止文本换行 */
overflow: hidden; /* 隐藏溢出的内容 */
text-overflow: ellipsis; /* 显示省略符号来代表被修剪的文本 */
}
.time {
position: absolute;
......@@ -317,23 +296,112 @@ onMounted(() => {
width: 792px;
height: 402px;
padding: 23px 30px 25px 21px;
overflow: auto;
.social-item {
overflow-y: auto;
overflow-x: hidden;
.trump {
width: 740px;
height: 148px;
margin-bottom: 16px;
display: flex;
cursor: pointer;
img {
width: 36px;
height: 36px;
margin-right: 8.5px;
border-radius: 50%;
}
.social-item-main {
.trump-main {
width: 695.6px;
height: 148px;
background-image: url("./assets/title01bg.png");
padding: 11px 14px 12px 22.5px;
background-size: 100% 100%;
background-repeat: no-repeat;
background-size: cover;
position: relative;
.cl1 {
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
margin-bottom: 5px;
}
.cl2 {
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
}
.cl3 {
position: absolute;
top: 11px;
right: 14px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 30px;
color: rgb(95, 101, 108);
}
}
}
.mask {
width: 740px;
height: 76px;
margin-bottom: 16px;
display: flex;
img {
width: 36px;
height: 36px;
margin-right: 8.5px;
}
.mask-main {
width: 695.6px;
height: 76px;
background-image: url("./assets/title02bg.png");
padding: 11px 14px 12px 22.5px;
background-size: cover;
position: relative;
.cl1 {
font-size: 16px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
margin-bottom: 5px;
}
.cl2 {
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(59, 65, 75);
}
.cl3 {
position: absolute;
top: 11px;
right: 14px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 30px;
color: rgb(95, 101, 108);
}
}
}
.malaby {
width: 740px;
height: 98px;
margin-bottom: 16px;
display: flex;
img {
width: 36px;
height: 36px;
margin-right: 8.5px;
}
.malaby-main {
width: 695.6px;
height: 98px;
background-image: url("./assets/title03bg.png");
padding: 11px 14px 12px 22.5px;
background-size: cover;
position: relative;
.cl1 {
font-size: 16px;
......@@ -366,3 +434,23 @@ onMounted(() => {
}
}
</style>
<style>
.common-prompt-popper.el-popper {
padding: 8px 16px !important;
border-radius: 10px !important;
background-color: rgb(59, 65, 75) !important;
font-size: 16px !important;
font-weight: 400 !important;
font-family: "Microsoft YaHei" !important;
line-height: 30px !important;
color: #fff !important;
border: none !important;
max-width: 1000px;
}
.common-prompt-popper.el-popper .el-popper__arrow::before {
background-color: rgb(59, 65, 75) !important;
border-color: rgb(59, 65, 75) !important;
}
</style>
<template>
<div class="data-new">
<div class="left">
<img src="./assets/leftbtn.png" alt="" class="left-btn" @click="handlePrev" />
<img src="./assets/rightbtn.png" alt="" class="right-btn" @click="handleNext" />
<img src="./assets/leftbtn.png" alt class="left-btn" @click="changeIndex(-1)" />
<img src="./assets/rightbtn.png" alt class="right-btn" @click="changeIndex(1)" />
<div class="left-top">
<img src="./assets/icon01.png" alt="" />
<img src="./assets/icon01.png" alt />
<div class="left-top-title">规则限制动态</div>
<div class="more" @click="handleClickToDetail">查看详情 ></div>
</div>
<el-carousel
ref="carouselRef"
height="412px"
direction="horizontal"
:autoplay="true"
:interval="5000"
arrow="never"
indicator-position="none"
@change="handleCarouselChange"
>
<el-carousel-item v-for="(item, index) in riskSignalList" :key="item.RULEID || index">
<div class="carousel-item-content">
<div class="left-center">
<img :src="item.PUBLISHORGIMGURL || defaultImg" alt="" />
<div class="left-center-main">
<div class="left-center-main-title">
{{ item.RULENAMEZH || "暂无动态" }}
</div>
<div class="left-center-main-ul">
<ul>
<li>
<span class="ul-title">发布机构:</span>
<span class="ul-content">{{ item.PUBLISHORGNAME || "未知" }}</span>
</li>
<li>
<span class="ul-title">发布日期:</span>
<span class="ul-content">{{ item.PUBLISHDATE || "未知" }}</span>
</li>
<li>
<span class="ul-title">涉及领域:</span>
<div class="ul-tags" v-if="item.ruleAreas && item.ruleAreas.length > 0">
<span
v-for="(field, fIndex) in item.ruleAreas"
:key="fIndex"
class="ul-pie"
:class="'cl' + ((fIndex % 4) + 1)"
>
{{ field }}
</span>
</div>
<span v-else class="ul-content">未知</span>
</li>
<li>
<span class="ul-title">限制实体:</span>
<span class="ul-content">
{{
item.ruleEntities && item.ruleEntities.length > 0
? item.ruleEntities.map(e => e.ORGNAME).join("、")
: "未知"
}}
</span>
</li>
</ul>
</div>
</div>
</div>
<div class="left-bottom">
<ul>
<li class="left-bottom-li">内容摘要:</li>
</ul>
<div class="left-bottom-content">
{{ item.RULEINTRODUCTION || "暂无内容摘要" }}
</div>
</div>
</div>
</el-carousel-item>
<!-- 无数据时的占位展示 -->
<el-carousel-item v-if="riskSignalList.length === 0">
<div class="carousel-item-content">
<div class="left-center">
<img :src="defaultImg" alt="" />
<div class="left-center-main">
<div class="left-center-main-title">暂无规则限制动态</div>
<div class="left-center-main-ul">
<ul>
<li><span class="ul-title">发布机构:</span><span class="ul-content">未知</span></li>
<li><span class="ul-title">发布日期:</span><span class="ul-content">未知</span></li>
<li><span class="ul-title">涉及领域:</span><span class="ul-content">未知</span></li>
<li><span class="ul-title">限制实体:</span><span class="ul-content">未知</span></li>
</ul>
</div>
</div>
</div>
<div class="left-center">
<img src="./assets/usImg.png" alt />
<div class="left-center-main">
<div class="left-center-main-title">{{ latestUpdateList[latestUpdateIndex].RULENAMEZH }}</div>
<div class="left-center-main-ul">
<ul>
<li>
<span class="ul-title">发布机构:</span>
<span class="ul-content">{{ latestUpdateList[latestUpdateIndex].PUBLISHORGNAME }}</span>
</li>
<li>
<span class="ul-title">发布日期:</span>
<span class="ul-content">{{ latestUpdateList[latestUpdateIndex].PUBLISHDATE }}</span>
</li>
<li>
<span class="ul-title">涉及领域:</span>
<span
class="ul-pie cl1"
v-for="item in latestUpdateList[latestUpdateIndex].ruleAreas"
>{{ item }}</span>
<!-- <span class="ul-pie cl2">集成电路</span>
<span class="ul-pie cl3">新材料</span>
<span class="ul-pie cl4">生物科技</span>-->
</li>
<li>
<span class="ul-title">限制实体:</span>
<span
class="ul-content"
v-for="item in latestUpdateList[latestUpdateIndex].ruleEntities"
>{{ item.ORGNAME }} &nbsp;</span>
</li>
</ul>
</div>
</el-carousel-item>
</el-carousel>
</div>
<!-- <div class="left-center-title">国会法案</div> -->
</div>
<div class="left-bottom">
<ul>
<li class="left-bottom-li">内容摘要:</li>
</ul>
<div class="left-bottom-content">{{ latestUpdateList[latestUpdateIndex].RULEINTRODUCTION }}</div>
</div>
</div>
<div class="right">
<div class="right-top">
<img src="./assets/icon02.png" alt="" />
<img src="./assets/icon02.png" alt />
<div class="right-top-title">
风险信号
<span>{{ riskSignals.length }}</span>
<span>{{ list.length }}</span>
</div>
</div>
<div style="margin: 6px 34px 0 23px">
<div v-for="item in riskSignals" :key="item.id" class="right-main" @click="handleToRiskDetail(item)">
<div v-for="(item, index) in list" :key="index" class="right-main">
<div
class="main-left"
:class="{ cl4: item.title === '特别重大', cl5: item.title === '重大风险', cl6: item.title === '一般风险' }"
>
{{ item.title }}
</div>
<div class="item-right">
<div class="main-center">
<CommonPrompt :content="item.content">
{{ item.content }}
</CommonPrompt>
</div>
<div class="main-right">{{ item.time }}</div>
</div>
:class="{ cl4: item.signalLevel === '特别重大', cl5: item.signalLevel === '重大风险', cl6: item.signalLevel === '一般风险'}"
>{{ item.signalLevel }}</div>
<div class="main-center">{{ item.signalTitle }}</div>
<div class="main-right">{{ item.signalTime }}</div>
</div>
</div>
<div class="right-mainbtn" @click="handleToMoreRiskSignal">
<img src="./assets/btn.png" alt="" />
<img src="./assets/btn.png" alt />
查看更多
</div>
</div>
......@@ -132,65 +78,94 @@
</template>
<script setup>
import { ref, onMounted, computed } from "vue";
import { ref, onBeforeMount, computed } from "vue";
import router from "@/router";
import { getRuleRestrictionLatest, getRuleRestrictionRiskSignal } from "@/api/ruleRestriction/ruleRestriction";
import defaultImg from "./assets/usImg.png";
import CommonPrompt from "../../commonPrompt/index.vue";
import { getLatestUpdates, getRiskSignal } from '@/api/ruleRestriction/index.js'
// 规则限制-查询风险信号数据
const riskSignals = ref([]);
const getRuleRestrictionRiskSignalData = async () => {
try {
const res = await getRuleRestrictionRiskSignal({ moduleId: "0108" });
if (res && res.code === 200) {
riskSignals.value = (res.data || []).map(item => ({
id: item.signalId,
title: item.signalLevel,
content: item.signalTitle,
time: item.signalTime,
ruleLimitId: item.ruleLimitId
}));
}
} catch (error) {
console.error("获取规则限制风险信号数据失败:", error);
}
};
const list = ref([
{
id: 1,
title: "特别重大",
content: "保护美国资金与专业知识免受敌对研究利用法案",
time: "一天前"
},
{
id: 2,
title: "特别重大",
content: "美国国土安全部终止哈佛大学SEVP认证",
time: "一天前"
},
{
id: 3,
title: "重大风险",
content: "众议院“美中战略竞争特别委员会”向国会提...",
time: "一天前"
},
{
id: 4,
title: "重大风险",
content: '2026财年拨款法案要求重启"中国行动计划"',
time: "一天前"
}
]);
// 最新动态列表
const latestUpdateList = ref([{}])
// 当前显示最新动态的序号
const latestUpdateIndex = ref(0)
// 改变序号
const changeIndex = (num) => {
if (num === -1) {
// 判断当前是否是第一个,是的话则将序号设置为最后一个
if (latestUpdateIndex.value === 0) {
latestUpdateIndex.value = latestUpdateList.value.length - 1
} else {
latestUpdateIndex.value--
}
} else {
// 判断当前是否是最后一个,是的话则将序号设置为第一个
if (latestUpdateIndex.value === latestUpdateList.value.length - 1) {
latestUpdateIndex.value = 0
} else {
latestUpdateIndex.value++
}
}
}
// 规则限制-获取规则限制动态
const riskSignalList = ref([]);
const carouselRef = ref(null);
const activeIndex = ref(0);
const getRuleRestrictionLatestData = async () => {
try {
const res = await getRuleRestrictionLatest();
if (res && res.code === 200) {
riskSignalList.value = res.data || [];
}
} catch (error) {
console.error("获取规则限制动态数据失败:", error);
}
};
const getLatestUpdateInfo = async () => {
try {
const res = await getLatestUpdates();
// console.log('------getLatestUpdateInfo res', res)
if (res && res.code === 200) {
console.log('----getLatestUpdateInfo', res.data)
latestUpdateList.value = res.data
}
} catch (error) {
console.error("获取最新动态接口失败:", error);
}
}
// 轮播图手动切换
const handlePrev = () => {
if (carouselRef.value) {
carouselRef.value.prev();
}
};
const handleNext = () => {
if (carouselRef.value) {
carouselRef.value.next();
}
};
const getRiskSignalInfo = async () => {
try {
const res = await getRiskSignal('0108');
console.log('------getRiskSignalInfo res', res)
if (res && res.code === 200) {
console.log('----getRiskSignalInfo', res.data)
list.value = res.data
}
} catch (error) {
console.error("获取风险信号接口失败:", error);
}
}
// 轮播切换回调
const handleCarouselChange = index => {
activeIndex.value = index;
};
// // 跳转详情
// const handleClickToDetail = () => {
// // router.push("/decreeLayout");
// // const route = router.resolve("");
// window.open(`/ruleRestrictions/detail?id=${latestUpdateList.value[latestUpdateIndex.value].RULEID}`, "_blank");
// };
// 左侧展示的主动态
const mainTrend = computed(() => {
......@@ -198,11 +173,6 @@ const mainTrend = computed(() => {
return riskSignalList.value[activeIndex.value] || riskSignalList.value[0];
});
onMounted(() => {
getRuleRestrictionLatestData();
getRuleRestrictionRiskSignalData();
});
// 点击风险信号详情
const handleToRiskDetail = (item) => {
const curRoute = router.resolve({
......@@ -228,9 +198,14 @@ const handleClickToDetail = item => {
// 查看更多动态
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
window.open(route.href, "_blank");
const route = router.resolve("/riskSignal");
window.open(route.href, "_blank");
};
onBeforeMount(async () => {
await getLatestUpdateInfo()
await getRiskSignalInfo()
})
</script>
<style scoped lang="scss">
......@@ -514,7 +489,7 @@ const handleToMoreRiskSignal = () => {
.right-main {
width: 468px;
padding-right: 5px;
height: 47px;
// height: 47px;
border-radius: 2px;
display: flex;
align-items: center;
......@@ -524,7 +499,7 @@ const handleToMoreRiskSignal = () => {
}
.main-left {
width: 40px;
height: 40px;
// height: 40px;
margin: 4px 13px 3px 2px;
border-radius: 50%;
font-size: 12px;
......@@ -542,40 +517,29 @@ const handleToMoreRiskSignal = () => {
background-color: rgba(255, 247, 230, 1);
color: rgba(250, 140, 22, 1);
}
.cl6 {
background-color: rgba(246, 255, 237, 1);
color: rgba(82, 196, 26, 1);
.cl6 {
background-color: rgba(255, 247, 230, 1);
color: rgb(22, 223, 250);
}
.item-right {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
.main-center {
flex: 1;
height: 30px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 30px;
color: rgb(59, 65, 75);
margin-right: 10px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.main-right {
width: 100px;
height: 24px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(132, 136, 142);
text-align: right;
flex-shrink: 0;
}
.main-center {
width: 347px;
// height: 30px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 30px;
color: rgb(59, 65, 75);
margin-right: 2px;
}
.main-right {
width: 60px;
// height: 24px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(132, 136, 142);
text-align: right;
}
}
.right-mainbtn {
......
......@@ -2,74 +2,71 @@
<div class="datasub">
<div class="left">
<div class="left-title">
<img src="./assets/icon01.png" alt="" />
<img src="./assets/icon01.png" alt />
<div class="tit">各类型合作限制政策对比</div>
<el-select v-model="value1" placeholder="Select" class="select">
<el-option v-for="item in options1" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="left-main">
<div class="left-main-echarts" ref="leftChartRef"></div>
</div>
<div class="left-main">
<div class="left-main-echarts" ref="leftChartRef"></div>
</div>
</div>
<div class="right">
<div class="right-title">
<img src="./assets/icon02.png" alt="" />
<img src="./assets/icon02.png" alt />
<div class="tit">各领域规则分布情况</div>
<el-select v-model="value2" placeholder="Select" class="select1">
<el-select v-model="value2" placeholder="Select" class="select1">
<el-option v-for="item in options2" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-select v-model="value" placeholder="Select" class="select">
<el-select v-model="value" placeholder="Select" class="select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="right-main">
<div class="right-main-echarts" ref="rightChartRef"></div>
</div>
<div class="right-main">
<div class="right-main-echarts" ref="rightChartRef"></div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import { ref, onMounted, onBeforeUnmount, watch } from "vue";
import * as echarts from "echarts";
import { getAreaDistribution, getEntityChangeTrend } from '@/api/ruleRestriction/index.js'
const value = ref("近十年");
const value1 = ref("2025");
const value2 = ref("全部限制手段");
const value = ref(10);
const value1 = ref("2025");
const value2 = ref("01");
const options = [
{
value: "近十年",
label: "近十年"
},
{
value: "近五年",
label: "近五年"
}
{
value: 10,
label: "近十年"
},
{
value: 5,
label: "近五年"
}
];
const options1 = [
{
value: "2025年",
label: "2025年"
},
{
value: "2024年",
label: "2024年"
}
{
value: "2025",
label: "2025年"
},
{
value: "2024",
label: "2024年"
}
];
const options2 = [
{
value: "全部限制手段",
label: "全部限制手段"
},
{
value: "人工智能",
label: "人工智能"
},
{
value: "集成电路",
label: "集成电路"
}
{
value: "01",
label: "行政令"
},
{
value: "02",
label: "法案"
}
];
const leftChartRef = ref(null);
......@@ -77,268 +74,330 @@ const rightChartRef = ref(null);
let leftChart;
let rightChart;
const initLeftDonut = () => {
if (!leftChartRef.value) return;
if (leftChart) leftChart.dispose();
leftChart = echarts.init(leftChartRef.value);
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 colors = [
"rgba(105, 177, 255, 1)", // 集成电路
"rgba(255, 192, 105, 1)", // 人工智能
"rgba(135, 232, 222, 1)", // 通信网络
"rgba(89, 126, 247, 1)", // 能源
"rgba(214, 228, 255, 1)", // 先进制造
"rgba(255, 120, 117, 1)", // 生物科技
"rgba(179, 127, 235, 1)", // 航空航天
"rgba(255, 163, 158, 1)" // 新材料
];
const option = {
color: colors,
tooltip: { trigger: "item", formatter: ({ name, value, percent }) => `${name}<br/>${value}${percent}%` },
series: [{
type: "pie",
radius: [96, 120],
center: ["50%", "50%"],
avoidLabelOverlap: true,
itemStyle: { borderWidth: 0 },
label: {
show: true,
position: "outside",
alignTo: 'edge',
formatter: ({ name, value, percent }) => `{name|${name}} {value|${value}项} {percent|${percent}%}`,
minMargin: 5,
edgeDistance: 10,
lineHeight: 15,
rich: {
name: { fontSize: 16, fontFamily: "Microsoft YaHei", fontWeight: 700, lineHeight: 24, color: "rgb(59, 65, 75)" },
value: { fontSize: 14, fontFamily: "Microsoft YaHei", fontWeight: 400, lineHeight: 22, color: "rgb(95, 101, 108)" },
percent: { fontSize: 14, fontFamily: "Microsoft YaHei", fontWeight: 400, lineHeight: 22, color: "rgb(95, 101, 108)" }
}
},
labelLine: {
show: true,
length: 30,
length2: 0,
maxSurfaceAngle: 80
},
labelLayout: function (params) {
const isLeft = params.labelRect.x < leftChart.getWidth() / 2;
const points = params.labelLinePoints;
// 导航线终点在标签下方
const lineY = params.labelRect.y + params.labelRect.height;
points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
points[2][1] = lineY;
points[1][1] = lineY;
return {
labelLinePoints: points
};
},
data: data.map((d, i) => ({
...d,
labelLine: { lineStyle: { color: colors[i], width: 1 } }
}))
}]
};
leftChart.setOption(option);
const colors = [
{
name: '集成电路',
value: "rgba(105, 177, 255, 1)",
},
{
name: '新一代通信网络',
value: "rgba(135, 232, 222, 1)",
},
{
name: '人工智能',
value: "rgba(255, 192, 105, 1)",
},
{
name: '能源',
value: "rgba(89, 126, 247, 1)",
},
{
name: '先进制造',
value: "rgba(214, 228, 255, 1)",
},
{
name: '生物科技',
value: "rgba(255, 120, 117, 1)",
},
{
name: '航空航天',
value: "rgba(179, 127, 235, 1)",
},
{
name: '新材料',
value: "rgba(255, 163, 158, 1)",
}
];
const initLeftDonut = async () => {
if (!leftChartRef.value) return;
if (leftChart) leftChart.dispose();
leftChart = echarts.init(leftChartRef.value);
let data = []
try {
const params = {
year: value1.value
}
const res = await getAreaDistribution(params);
if (res && res.code === 200) {
console.log('----getAreaDistribution', res.data)
for (let i = 0; i < res.data.length; i++) {
let item = {
name: '',
value: 0
}
item.name = res.data[i].AREANAME
item.value = res.data[i].AREACOUNT
item.itemStyle = {
color: getColor(colors, item.name)
}
data.push(item)
}
}
} catch (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 = {
tooltip: { trigger: "item", formatter: ({ name, value, percent }) => `${name}<br/>${value}${percent}%` },
series: [{
type: "pie",
radius: [96, 120],
center: ["50%", "50%"],
avoidLabelOverlap: true,
itemStyle: { borderWidth: 0 },
label: {
show: true,
position: "outside",
alignTo: 'edge',
formatter: ({ name, value, percent }) => `{name|${name}} {value|${value}项} {percent|${percent}%}`,
minMargin: 5,
edgeDistance: 10,
lineHeight: 15,
rich: {
name: { fontSize: 16, fontFamily: "Microsoft YaHei", fontWeight: 700, lineHeight: 24, color: "rgb(59, 65, 75)" },
value: { fontSize: 14, fontFamily: "Microsoft YaHei", fontWeight: 400, lineHeight: 22, color: "rgb(95, 101, 108)" },
percent: { fontSize: 14, fontFamily: "Microsoft YaHei", fontWeight: 400, lineHeight: 22, color: "rgb(95, 101, 108)" }
}
},
labelLine: {
show: true,
length: 30,
length2: 0,
maxSurfaceAngle: 80
},
labelLayout: function (params) {
const isLeft = params.labelRect.x < leftChart.getWidth() / 2;
const points = params.labelLinePoints;
// 导航线终点在标签下方
const lineY = params.labelRect.y + params.labelRect.height;
points[2][0] = isLeft ? params.labelRect.x : params.labelRect.x + params.labelRect.width;
points[2][1] = lineY;
points[1][1] = lineY;
return {
labelLinePoints: points
};
},
data: data.map((d, i) => ({
...d,
labelLine: { lineStyle: { color: getColor(colors, d.name), width: 1 } }
}))
}]
};
leftChart.setOption(option);
};
const initRightLine = () => {
if (!rightChartRef.value) return;
if (rightChart) rightChart.dispose();
rightChart = echarts.init(rightChartRef.value);
const years = ['2014', '2015', '2016', '2017', '2018', '2019', '2020', '2021', '2022', '2023', '2024', '2025'];
const seriesData = [
{ name: '人工智能', color: 'rgb(5, 95, 194)', data: [150, 90, 65, 95, 75, 95, 130, 150, 140, 170, 175, 185] },
{ name: '集成电路', color: 'rgba(19, 168, 168, 1)', data: [65, 95, 125, 115, 135, 145, 165, 165, 165, 175, 180, 175] },
{ name: '量子科技', color: 'rgba(114, 46, 209, 1)', data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 12] },
{ name: '生物科技', color: 'rgba(250, 140, 22, 1)', data: [12, 8, 8, 12, 12, 15, 20, 30, 25, 30, 42, 42] },
{ name: '通信网络', color: 'rgba(105, 177, 255, 1)', data: [42, 38, 45, 52, 52, 48, 52, 72, 65, 62, 65, 58] },
{ name: '能源', color: 'rgb(206, 79, 81)', data: [98, 75, 62, 82, 62, 72, 82, 122, 118, 148, 138, 105] }
];
const option = {
color: seriesData.map(s => s.color),
legend: {
top: 10,
left: 'center',
itemWidth: 12,
itemHeight: 12,
itemGap: 20,
icon: 'circle',
textStyle: {
fontSize: 16,
fontWeight: 400,
lineHeight: 24,
fontFamily: 'Microsoft YaHei',
color: 'rgb(95, 101, 108)'
}
},
grid: {
top: 60,
left: 50,
right: 40,
bottom: 40
},
xAxis: {
type: 'category',
data: years,
boundaryGap: false,
axisLine: {
lineStyle: { color: '#E5E7EB' }
},
axisLabel: {
color: 'rgba(132, 136, 142, 1)',
fontSize: 14,
fontWeight: 400,
lineHeight: 22,
fontFamily: 'Microsoft YaHei'
}
},
yAxis: {
type: 'value',
min: 0,
max: 200,
interval: 40,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
color: 'rgba(132, 136, 142, 1)',
fontSize: 14,
fontWeight: 400,
lineHeight: 22,
fontFamily: 'Microsoft YaHei'
},
splitLine: {
lineStyle: { color: '#E5E7EB' }
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line'
}
},
series: [
{
name: '人工智能',
type: 'line',
data: seriesData[0].data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(5, 95, 194, 0.25)' },
{ offset: 1, color: 'rgba(5, 95, 194, 0.05)' }
])
}
},
{
name: '集成电路',
type: 'line',
data: seriesData[1].data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(19, 168, 168, 0.25)' },
{ offset: 1, color: 'rgba(19, 168, 168, 0.05)' }
])
}
},
{
name: '量子科技',
type: 'line',
data: seriesData[2].data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(114, 46, 209, 0.25)' },
{ offset: 1, color: 'rgba(114, 46, 209, 0.05)' }
])
}
},
{
name: '生物科技',
type: 'line',
data: seriesData[3].data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(250, 140, 22, 0.25)' },
{ offset: 1, color: 'rgba(250, 140, 22, 0.05)' }
])
}
},
{
name: '通信网络',
type: 'line',
data: seriesData[4].data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(105, 177, 255, 0.25)' },
{ offset: 1, color: 'rgba(105, 177, 255, 0.05)' }
])
}
const initRightLine = async () => {
if (!rightChartRef.value) return;
if (rightChart) rightChart.dispose();
rightChart = echarts.init(rightChartRef.value);
// 首先根据现在的年份,然后再根据所选的年限生成years
const currentYear = new Date().getFullYear()
// 再根据年限往前倒退
const years = []
for (let i = value.value - 1; i >= 0; i--) {
const year = currentYear - i + ''
years.push(year)
}
console.log('----years', years)
// 根据后端生成的数据然后填充数据
const seriesData = []
let maxValue = 0
try {
const params = {
year: value.value,
type: value2.value
}
const res = await getEntityChangeTrend(params);
console.log('-----getEntityChangeTrendList res', res)
if (res && res.code === 200) {
console.log('----getEntityChangeTrendList', res.data)
// 对查询到的数据进行分类
for (let i = 0; i < res.data.length; i++) {
const item = res.data[i]
maxValue = Math.max(item.ENTITYCOUNT, maxValue)
// 优先遍历seriesData中是否已经存在name对象
const index = seriesData.findIndex((ele) => ele.name === item.AREANAME)
// console.log('---seriesData', i, JSON.stringify(seriesData), index)
if (index !== -1) {
const yearIndex = years.findIndex((y) => y === item.YEAR)
seriesData[index].data[yearIndex] = item.ENTITYCOUNT
} else {
const data = new Array(value.value).fill(0)
const yearIndex = years.findIndex((y) => y === item.YEAR)
data[yearIndex] = item.ENTITYCOUNT
// 新建
const color_ = getColor(colors, item.AREANAME)
// 以逗号划分为数组并修改最后一部分的值
const colorArray = color_.split(',')
const colorArray1 = JSON.parse(JSON.stringify(colorArray))
const colorArray2 = JSON.parse(JSON.stringify(colorArray))
colorArray1[colorArray1.length - 1] = '0.5)'
colorArray2[colorArray2.length - 1] = '0.1)'
const color1 = colorArray1.join(',')
const color2 = colorArray2.join(',')
console.log(item.AREANAME, '----color1 color2', color1, color2)
const options = {
name: item.AREANAME,
type: 'line',
data: data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: color1 },
{ offset: 1, color: color2 }
])
},
{
name: '能源',
type: 'line',
data: seriesData[5].data,
smooth: false,
symbol: 'circle',
symbolSize: 6,
lineStyle: { width: 2 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(206, 79, 81, 0.25)' },
{ offset: 1, color: 'rgba(206, 79, 81, 0.05)' }
])
}
itemStyle: {
color: color_
}
]
};
rightChart.setOption(option);
}
seriesData.push(options)
}
}
}
} catch (error) {
console.error("获取受限实体数量变化趋势接口失败:", error);
}
const option = {
color: colors.map((item) => {
return item.value
}),
legend: {
top: 10,
left: 'center',
itemWidth: 12,
itemHeight: 12,
itemGap: 20,
icon: 'circle',
textStyle: {
fontSize: 16,
fontWeight: 400,
lineHeight: 24,
fontFamily: 'Microsoft YaHei',
color: 'rgb(95, 101, 108)'
}
},
grid: {
top: 60,
left: 50,
right: 40,
bottom: 40
},
xAxis: {
type: 'category',
data: years,
boundaryGap: false,
axisLine: {
lineStyle: { color: '#E5E7EB' }
},
axisLabel: {
color: 'rgba(132, 136, 142, 1)',
fontSize: 14,
fontWeight: 400,
lineHeight: 22,
fontFamily: 'Microsoft YaHei'
}
},
yAxis: {
type: 'value',
min: 0,
max: maxValue * 1.5,
interval: maxValue * 0.5,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
color: 'rgba(132, 136, 142, 1)',
fontSize: 14,
fontWeight: 400,
lineHeight: 22,
fontFamily: 'Microsoft YaHei'
},
splitLine: {
lineStyle: { color: '#E5E7EB' }
}
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line'
}
},
series: seriesData
};
rightChart.setOption(option);
};
const handleResize = () => {
if (leftChart) leftChart.resize();
if (rightChart) rightChart.resize();
const getColor = (colors, name) => {
const index = colors.findIndex((i) => i.name === name)
if (index !== -1) {
return colors[index].value
} else {
return "rgba(105, 177, 255, 1)"
}
}
const handleResize = () => {
if (leftChart) leftChart.resize();
if (rightChart) rightChart.resize();
};
onMounted(() => {
initLeftDonut();
initRightLine();
window.addEventListener("resize", handleResize);
const getEntityChangeTrendList = async () => {
try {
const params = {
year: value.value,
type: value2.value
}
const res = await getEntityChangeTrend(params);
console.log('-----getEntityChangeTrendList res', res)
if (res && res.code === 200) {
console.log('----getEntityChangeTrendList', res.data)
}
} catch (error) {
console.error("获取受限实体数量变化趋势接口失败:", error);
}
}
watch(value1, () => {
initLeftDonut()
})
watch([value, value2], () => {
initRightLine()
})
onMounted(async () => {
await initLeftDonut();
await initRightLine();
window.addEventListener("resize", handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize);
if (leftChart) { leftChart.dispose(); leftChart = null; }
if (rightChart) { rightChart.dispose(); rightChart = null; }
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize);
if (leftChart) { leftChart.dispose(); leftChart = null; }
if (rightChart) { rightChart.dispose(); rightChart = null; }
});
</script>
......@@ -382,24 +441,24 @@ onBeforeUnmount(() => {
line-height: 26px;
color: rgb(5, 95, 194);
}
.select {
width: 120px;
height: 28px;
padding: 0px 12px;
position: absolute;
top: 11px;
right: 31px;
}
.select {
width: 120px;
height: 28px;
padding: 0px 12px;
position: absolute;
top: 11px;
right: 31px;
}
}
.left-main {
width: 792px;
height: 412px;
padding: 52px 60px 78px 61px;
.left-main-echarts {
width: 100%;
height: 100%;
}
}
.left-main {
width: 792px;
height: 412px;
padding: 52px 60px 78px 61px;
.left-main-echarts {
width: 100%;
height: 100%;
}
}
}
.right {
width: 792px;
......@@ -408,11 +467,11 @@ onBeforeUnmount(() => {
// border: 1px solid rgb(234, 236, 238);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background-color: #fff;
.right-title {
width: 792px;
height: 48px;
border-bottom: 1px solid rgb(234, 236, 238);
position: relative;
.right-title {
width: 792px;
height: 48px;
border-bottom: 1px solid rgb(234, 236, 238);
position: relative;
img {
width: 19px;
height: 19px;
......@@ -420,42 +479,42 @@ onBeforeUnmount(() => {
top: 16px;
left: 21px;
}
.tit {
margin-left: 60px;
height: 48px;
padding: 11px 0;
font-size: 20px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 26px;
color: rgb(5, 95, 194);
}
.select1 {
width: 155px;
height: 28px;
padding: 0px 12px;
position: absolute;
top: 11px;
right: 163px;
}
.select {
width: 120px;
height: 28px;
padding: 0px 12px;
position: absolute;
top: 11px;
right: 31px;
}
.tit {
margin-left: 60px;
height: 48px;
padding: 11px 0;
font-size: 20px;
font-weight: 700;
font-family: "Microsoft YaHei";
line-height: 26px;
color: rgb(5, 95, 194);
}
.select1 {
width: 155px;
height: 28px;
padding: 0px 12px;
position: absolute;
top: 11px;
right: 163px;
}
.select {
width: 120px;
height: 28px;
padding: 0px 12px;
position: absolute;
top: 11px;
right: 31px;
}
}
.right-main {
width: 792px;
height: 421px;
padding: 15px 37px 25px 46px;
.right-main-echarts {
width: 100%;
height: 100%;
}
}
.right-main {
width: 792px;
height: 421px;
padding: 15px 37px 25px 46px;
.right-main-echarts {
width: 100%;
height: 100%;
}
}
}
}
</style>
......@@ -7,9 +7,7 @@
class="nav-item"
:class="{ active: item === activeItem }"
@click="handleClickNav(item)"
>
{{ item }}
</div>
>{{ item }}</div>
</div>
<el-select v-model="value" placeholder="Select" class="select">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
......@@ -20,49 +18,55 @@
<div class="left-ti2"></div>
<div class="left-title">发布时间</div>
<div class="left-content">
<div v-for="(item, i) in dataList" :key="item.id" class="left-item">
<input type="checkbox" :checked="i === 0" />{{ item.name }}
</div>
<el-checkbox
v-for="(item, index) in dataList"
:key="index"
v-model="item.checked"
:label="item.label"
@change="handleFilterChange(item, dataList)"
/>
</div>
<div class="left-title cl1">涉及领域</div>
<div class="left-content">
<div v-for="(item, i) in dataList2" :key="item.id" class="left-item">
<input type="checkbox" :checked="i === 0" />{{ item.name }}
</div>
<el-checkbox
v-for="(item, index) in techFields"
:key="index"
v-model="item.checked"
:label="item.label"
@change="handleFilterChange(item, techFields)"
/>
</div>
</div>
<div class="right">
<div class="right-title">
<img src="./assets/icon01.png" alt="" />
<img src="./assets/icon01.png" alt />
<div>规则限制历程</div>
</div>
<div class="right-main">
<div class="main-content">
<div v-for="item in mainDataList" :key="item.id" class="main-item">
<div class="date">{{ item.date }}</div>
<img :src="item.img" alt="" class="img" />
<div class="date">{{ getDate(item) }}</div>
<img :src="item.ORGPICTURE" alt class="img" />
<div class="box">
<div class="title" @click="handleClick(item)">{{ item.title }}</div>
<div class="content" @click="handleClick(item)">{{ item.content }}</div>
<div class="title">{{ item.RULENAME }}</div>
<div class="content">{{ item.RULEINTRODUCTION }}</div>
<div class="domain">
<div v-for="(domain, i) in item.domain" :key="i" class="domain-item">{{ domain }}</div>
<div v-for="(domain, i) in item.ruleAreas" :key="i" class="domain-item">{{ domain }}</div>
</div>
<div
class="type"
:class="{
type1: item.type === '行政令',
type2: item.type === '法案',
type3: item.type === '301调查'
type1: item.RULEMEANS === '行政令',
type2: item.RULEMEANS === '法案',
type3: item.RULEMEANS === '301调查'
}"
>
{{ item.type }}
</div>
>{{ item.RULEMEANS }}</div>
</div>
</div>
</div>
<div class="line"></div>
<div class="page">
<div class="count"> {{ total }}</div>
<div class="count">{{ total }}项调查</div>
<el-pagination
v-model:current-page="currentPage"
:page-size="pageSize"
......@@ -82,53 +86,68 @@
<div class="left-ti3"></div>
<div class="left-title">发布时间</div>
<div class="left-content">
<div v-for="(item, i) in dataList" :key="item.id" class="left-item">
<input type="checkbox" :checked="i === 0" />{{ item.name }}
</div>
<el-checkbox
v-for="(item, index) in dataList"
:key="index"
v-model="item.checked"
:label="item.label"
@change="handleFilterChange(item, dataList)"
/>
</div>
<div class="left-title cl1">涉及领域</div>
<div class="left-content">
<div v-for="(item, i) in dataList2" :key="item.id" class="left-item">
<input type="checkbox" :checked="i === 0" />{{ item.name }}
</div>
<el-checkbox
v-for="(item, index) in techFields"
:key="index"
v-model="item.checked"
:label="item.label"
@change="handleFilterChange(item, techFields)"
/>
</div>
<div class="left-title cl2">涉及国家</div>
<div class="left-content">
<div v-for="(item, i) in dataList3" :key="item.id" class="left-item">
<input type="checkbox" :checked="i === 0" />{{ item.name }}
</div>
<el-checkbox
v-for="(item, index) in dataList3"
:key="index"
v-model="item.checked"
:label="item.label"
@change="handleFilterChange(item, dataList3)"
/>
</div>
</div>
<div class="right-unshow">
<div class="top">
<div v-for="item in unionDataList" :key="item.id" class="top-item">
<div class="title">
<img :src="item.img" alt="" />
<div>
<span class="name">{{ item.name }}</span
><span class="abb">{{ item.abb }}</span>
<div class="compose">{{ item.compose }}</div>
<div class="img-list">
<img class="img-style" :src="ele.COUNTRYIMAGE" v-for="ele in item.countries" alt />
</div>
<div
class="type"
:class="{
type1: item.type === '通信网络',
type2: item.type === '集成电路',
type3: item.type === ''
}"
>
{{ item.type }}
<div style="width: calc(100% - 60px)">
<div style="display: flex; justify-content: space-between;">
<div>
<span class="name">{{ item.ACTANAME }}</span>
<span class="abb">{{ item.ACTASHORTNAMEEN }}</span>
</div>
<div class="type">
<div
v-for="(ele, index) in item.area"
:key="index"
:class="{ type1: ele !== '', type3: ele === '' }"
>{{ ele }}</div>
</div>
</div>
<div class="compose">{{ getCompose(item) }}</div>
</div>
</div>
<div class="content">{{ item.content }}</div>
<div class="content">{{ item.ACTAINTRODUCTION }}</div>
</div>
</div>
<div class="bottom">
<div class="count"> {{ total }}</div>
<div class="count">{{ unionDataList.length }}项调查</div>
<el-pagination
v-model:current-page="currentPage"
:page-size="pageSize"
:total="total"
v-model:current-page="currentPageACTA"
:page-size="pageSizeACTA"
:total="totalACTA"
layout="prev, pager, next"
background
@current-change="handlePageChange"
......@@ -140,381 +159,341 @@
</template>
<script setup>
import { ref } from "vue";
import { ref, onMounted, watch } from "vue";
import { useRouter } from "vue-router";
// import whitehouse from "./assets/白宫.png";
// import guohui from "./assets/国会.png";
// import guotuanquanbu from "./assets/国土安全部.png";
// import guowuyuan from "./assets/国务院.png";
// import weishengyanjiuyuan from "./assets/卫生研究院.png";
// import zhongyiyuan from "./assets/众议院.png";
import fda from "./assets/FDA.png";
import swb from "./assets/商务部.png";
import fcc from "./assets/FCC.png";
import flag01 from "./assets/flag01.png";
import flag02 from "./assets/flag02.png";
import flag03 from "./assets/flag03.png";
import flag04 from "./assets/flag04.png";
import flag05 from "./assets/flag05.png";
import flag06 from "./assets/flag06.png";
import flag07 from "./assets/flag07.png";
import flag08 from "./assets/flag08.png";
import flag09 from "./assets/flag09.png";
import flag01 from "./assets/flag01.png"
import flag02 from "./assets/flag02.png"
import flag03 from "./assets/flag03.png"
import flag04 from "./assets/flag04.png"
import flag05 from "./assets/flag05.png"
import flag06 from "./assets/flag06.png"
import flag07 from "./assets/flag07.png"
import flag08 from "./assets/flag08.png"
import flag09 from "./assets/flag09.png"
import { getRuleLimitList, getACTAList, getAcTAAllcountry } from '@/api/ruleRestriction/index.js'
const router = useRouter();
const handleClick = item => {
router.push({
path: "/ruleRestrictions/detail",
query: {
id: item.id
}
});
router.push({
path: "/ruleRestrictions/detail",
query: {
id: item.RULEID
}
});
};
const isShow = ref(true);
const navList = ref(["规则限制政令", "排华科技联盟"]);
const activeItem = ref("规则限制政令");
const handleClickNav = item => {
activeItem.value = item;
if (item === "规则限制政令") {
isShow.value = true;
} else {
isShow.value = false;
}
activeItem.value = item;
if (item === "规则限制政令") {
isShow.value = true;
getRuleLimitListApi()
} else {
isShow.value = false;
getACTAListInfo()
}
};
const value = ref("发布时间");
const value = ref("desc");
const options = [
{
value: "发布时间",
label: "发布时间"
},
{
value: "发布日期",
label: "发布日期"
}
{
value: "asc",
label: "时间正序"
},
{
value: "desc",
label: "时间倒序"
}
];
const dataList = ref([
{
id: 1,
name: "全部时间"
},
{
id: 2,
name: "2025年"
},
{
id: 3,
name: "2024年"
},
{
id: 4,
name: "2023年"
},
{
id: 5,
name: "2022年"
},
{
id: 6,
name: "2021年"
},
{
id: 7,
name: "2020年"
},
{
id: 8,
name: "更早"
}
{ label: "全部时间", value: "all", checked: true },
{ label: "2025年", value: "2025", checked: false },
{ label: "2024年", value: "2024", checked: false },
{ label: "2023年", value: "2023", checked: false },
{ label: "2022年", value: "2022", checked: false },
{ label: "2021年", value: "2021", checked: false }
]);
const dataList2 = ref([
{
id: 1,
name: "全部领域"
},
{
id: 2,
name: "人工智能"
},
{
id: 3,
name: "集成电路"
},
{
id: 4,
name: "通信网络"
},
{
id: 5,
name: "量子科技"
},
{
id: 6,
name: "能源"
},
{
id: 7,
name: "生物科技"
},
{
id: 8,
name: "航空航天"
},
{
id: 9,
name: "海洋"
},
{
id: 10,
name: "先进制造"
}
const techFields = ref([
{ label: "全部领域", value: "all", checked: true },
{ label: "人工智能", value: "1", checked: false },
{ label: "生物科技", value: "2", checked: false },
{ label: "新一代通信网络", value: "3", checked: false },
{ label: "量子科技", value: "4", checked: false },
{ label: "新能源", value: "5", checked: false },
{ label: "集成电路", value: "6", checked: false },
{ label: "海洋", value: "7", checked: false },
{ label: "先进制造", value: "8", checked: false },
{ label: "新材料", value: "9", checked: false },
{ label: "航空航天", value: "10", checked: false },
{ label: "深海", value: "11", checked: false },
{ label: "极地", value: "12", checked: false },
{ label: "太空", value: "13", checked: false },
{ label: "核", value: "14", checked: false },
{ label: "其他", value: "99", checked: false }
]);
const dataList3 = ref([
{
id: 1,
name: "全部国家"
},
{
id: 2,
name: "美国"
},
{
id: 3,
name: "日本"
},
{
id: 4,
name: "韩国"
},
{
id: 5,
name: "英国"
},
{
id: 6,
name: "澳大利亚"
},
{
id: 7,
name: "新西兰"
},
{
id: 8,
name: "加拿大"
},
{
id: 9,
name: "欧盟"
},
{
id: 10,
name: "中国台湾"
}
{
"value": "all",
"label": "全部国家",
checked: true
},
{
"value": "0103",
"label": "韩国",
checked: false
},
{
"value": "0104",
"label": "日本",
checked: false
},
{
"label": "印度",
"value": "0119",
checked: false
},
{
"value": "0203",
"label": "瑞典",
checked: false
},
{
"value": "0204",
"label": "芬兰",
checked: false
},
{
"label": "英国",
"value": "0217",
checked: false
},
{
"value": "0220",
"label": "荷兰",
checked: false
},
{
"value": "0222",
"label": "法国",
checked: false
},
{
"value": "0401",
"label": "澳大利亚",
checked: false
},
{
"value": "0501",
"label": "加拿大",
checked: false
},
{
"value": "0502",
"label": "美国",
checked: false
},
{
"value": "010101",
"label": "中国台湾",
checked: false
}
]);
const mainDataList = ref([
{
id: 1,
title: "美国FDA:针对两家中国第三方检测机构的数据完整性问题采取行动",
content:
"FDA因发现数据伪造或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏州大学卫生与环境技术研究所)正式发出“一般信函”。",
date: "2025年10月15日",
domain: ["生物科技"],
type: "行政令",
img: fda
},
{
id: 2,
title: "美国商务部:扩大实体清单制裁范围,对中企子公司实施同等管制",
content:
"任何被列入美国出口管制“实体清单”或“军事最终用户清单”的企业,如果其直接或间接持有另一家公司 ​50%或以上的股权,那么这家被控股的公司也将自动受到与清单上母公司同等的出口管制限制",
date: "2025年9月30日",
domain: ["生物科技"],
type: "301调查",
img: swb
},
{
id: 3,
title: "美国商务部:出台全面半导体出口管制",
content: "美国商务部宣称将“至少每年”更新一次管制规则,以堵塞已发现的政策“漏洞”。",
date: "2025年9月15日",
domain: ["生物科技"],
type: "行政令",
img: swb
},
{
id: 4,
title: "美国FCC:出台电信设备市场准入认证新规",
content: "将国家安全审查全面嵌入设备授权程序,对实验室资质、测试标准以及供应链设置严格限制。",
date: "2025年9月8日",
domain: ["生物科技", "通信网络"],
type: "行政令",
img: fcc
},
{
id: 5,
title: "美国FCC:发布“清洁购物车”行动,要求电商平台下架违规中国电子产品",
content:
"在亚马逊、eBay等美国主流电商平台销售的华为、海康威视、中兴、大华等中国品牌的消费电子产品(如家用监控摄像头、智能手表)。",
date: "2025年9月1日",
domain: ["集成电路", "人工智能", "通信网络"],
type: "行政令",
img: fcc
},
{
id: 6,
title: "美国FDA:紧急叫停涉及将美国公民活体细胞送往中国等“敌对国家”实验室的临床试验",
content: "涉及将人类生物样本(如活体细胞)转移至中国进行基因工程等研究的临床试验项目,相关研究被叫停。",
date: "2025年8月26日",
domain: ["生物科技"],
type: "行政令",
img: fda
},
{
id: 7,
title: "美国FDA:更新进口预警措施,对多家中国食品企业产品实施​“自动扣留”​​",
content:
"多家中国食品及农产品出口企业(如广东企业罗非鱼、辽宁企业宠物零食等),被扣留的货物必须在FDA或其认可的实验室内检验合格后方可放行。",
date: "2025年8月22日",
domain: ["生物科技"],
type: "行政令",
img: fda
},
{
id: 8,
title: "美国FCC:禁止使用清单内企业零部件的新设备获得授权,并首次可追溯撤销已获批设备的销售许可",
content: "对“受管制清单”实施技术性补封,建立​“回溯机制”​​ 并封闭​“模块发射器”漏洞。",
date: "2025年8月15日",
domain: ["通信网络"],
type: "行政令",
img: fcc
},
{
id: 9,
title: "美国FDA:针对两家中国第三方检测机构的数据完整性问题采取行动",
content:
"FDA因发现数据伪造或无效问题,向两家中国第三方检测公司(天津中联科技检测有限公司和苏州大学卫生与环境技术研究所)正式发出“一般信函”。",
date: "2025年10月15日",
domain: ["生物科技"],
type: "行政令",
img: fda
},
{
id: 10,
title: "美国商务部:出台全面半导体出口管制",
content: "美国商务部宣称将“至少每年”更新一次管制规则,以堵塞已发现的政策“漏洞”。",
date: "2025年9月15日",
domain: ["生物科技"],
type: "行政令",
img: swb
}
]);
const mainDataList = ref([]);
const unionDataList = ref([
{
id: 1,
name: "AI-RAN联盟",
abb: "QUAD",
compose: "2024年成立 · 美国、英国、日本、韩国、法国、加拿大等10国",
content:
"由英伟达牵头,联合软银、亚马逊云科技、微软、爱立信、诺基亚、三星、T-Mobile等多家行业领导者成立了的人工智能无线接入网络技术联盟。",
type: "通信网络",
img: flag01
},
{
id: 2,
name: "Next G联盟",
abb: "",
compose: "2021年成立 · 美国、瑞典、芬兰、韩国",
content: "在6G技术研发和未来标准制定上抢先布局,旨在主导6G发展方向,其联盟的排他性被解读为针对中国。",
type: "通信网络",
img: flag02
},
{
id: 3,
name: "美日印澳“四边机制”",
abb: "QUAD",
compose: "2021年成立 · 美国、日本、印度、澳大利亚",
content: "在地区安全、基础设施、新兴技术和供应链(特别是半导体)等领域开展排他性合作,筹备构建“印太版北约” 。",
type: "集成电路",
img: flag03
},
{
id: 4,
name: "美国半导体联盟",
abb: "SIAC",
compose: "2021年成立 · 美国、韩国、中国台湾、荷兰",
content:
"初始核心任务是游说美国政府对本土芯片产业提供补贴(如500亿美元的《芯片法案》),但其成员构成未纳入中国大陆企业,具有明显的“排华”倾向。",
type: "集成电路",
img: flag04
},
{
id: 5,
name: "Next G联盟",
abb: "",
compose: "2021年成立 · 美国、瑞典、芬兰、韩国",
content: "在6G技术研发和未来标准制定上抢先布局,旨在主导6G发展方向,其联盟的排他性被解读为针对中国。",
type: "通信网络",
img: flag05
},
{
id: 6,
name: "芯片四方联盟",
abb: "Chip 4",
compose: "2020年成立 · 美国、日本、韩国、中国台湾",
content: "构建将中国大陆排除在外的半导体供应链体系,意图在芯片设计、生产到供应环节形成闭环,限制先进芯片技术对华出口。",
type: "集成电路",
img: flag06
},
{
id: 7,
name: "美英澳三边安全伙伴关系",
abb: "AUKUS",
compose: "2020年成立 · 美国、英国、澳大利亚",
content: "美英两国支持澳大利亚建立核潜艇部队,旨在深化三国在安全和防务能力上的合作。",
type: "",
img: flag07
},
{
id: 8,
name: "印太经济框架",
abb: "IPEF",
compose: "2020年成立 · 美国、英国、澳大利亚",
content: "重点在供应链领域制定新协议,增强透明度与安全性,确保对半导体等关键产品和技术的获取,推动供应链“去中国化”。",
type: "集成电路",
img: flag08
},
{
id: 9,
name: "清洁网络计划",
abb: "",
compose: "2019年成立 · 美国、英国、荷兰",
content:
"在全球5G网络部署和软件应用生态中排除中国的企业和设备,涉及电信运营商、移动应用、应用商店、云服务和海底光缆等多个层面。",
type: "通信网络",
img: flag09
},
{
id: 10,
name: "清洁网络计划",
abb: "",
compose: "2019年成立 · 美国、英国、荷兰",
content:
"在全球5G网络部署和软件应用生态中排除中国的企业和设备,涉及电信运营商、移动应用、应用商店、云服务和海底光缆等多个层面。",
type: "通信网络",
img: flag09
}
]);
const unionDataList = ref([])
// 筛选逻辑处理
const handleFilterChange = (item, list) => {
// 如果点击的是"全部"
if (item.value === 'all') {
if (item.checked) {
// 选中全部,取消其他所有
list.forEach(i => {
if (i.value !== 'all') i.checked = false;
});
} else {
// 取消全部(通常不允许全部取消,至少得选一个,这里如果取消全部,就默认为全部选中)
item.checked = true;
}
} else {
// 点击的是具体项
if (item.checked) {
// 选中具体项,取消"全部"
const allItem = list.find(i => i.value === 'all');
if (allItem) allItem.checked = false;
} else {
// 取消具体项,检查是否还有选中的
const anyChecked = list.some(i => i.checked);
if (!anyChecked) {
const allItem = list.find(i => i.value === 'all');
if (allItem) allItem.checked = true;
}
}
}
// 重置页码并查询
currentPage.value = 0;
if (isShow.value) {
getRuleLimitListApi();
} else {
getACTAListInfo()
}
};
const getRuleLimitListApi = async () => {
// 处理科技领域筛选
let techDomains = [];
const allTech = techFields.value.find(item => item.value === 'all');
if (!allTech || !allTech.checked) {
techDomains = techFields.value
.filter(item => item.checked && item.value !== 'all')
.map(item => item.value);
}
// 处理发布时间时间筛选
let years = [];
const allTime = dataList.value.find(item => item.value === 'all');
if (!allTime || !allTime.checked) {
years = dataList.value
.filter(item => item.checked && item.value !== 'all')
.map(item => item.value);
}
const params = {
areas: techDomains.length > 0 ? techDomains.join(',') : undefined,
years: years.length > 0 ? years.join(',') : undefined,
keywords: undefined,
sortOrder: value.value,
sortField: 'date',
currentPage: currentPage.value,
pageSize: pageSize.value
};
try {
console.log('-----getRuleLimitList params', params)
const res = await getRuleLimitList(params);
console.log('-----getRuleLimitList res', res)
if (res.code === 200) {
console.log('-----getRuleLimitListApi', res.data)
total.value = res.data.numberOfElements
mainDataList.value = res.data.content
}
} catch (error) {
console.error("获取规则限制政令列表查询接口接口失败:", error);
}
}
const getACTAListInfo = async () => {
// 处理科技领域筛选
let techDomains = [];
const allTech = techFields.value.find(item => item.value === 'all');
if (!allTech || !allTech.checked) {
techDomains = techFields.value
.filter(item => item.checked && item.value !== 'all')
.map(item => item.value);
}
// 处理发布时间时间筛选
let years = [];
const allTime = dataList.value.find(item => item.value === 'all');
if (!allTime || !allTime.checked) {
years = dataList.value
.filter(item => item.checked && item.value !== 'all')
.map(item => item.value);
}
// 处理国家筛选
let countries = []
const allCountry = dataList3.value.find(item => item.value === 'all')
if (!allCountry || !allCountry.checked) {
countries = dataList3.value.filter(item => item.checked && item.value !== 'all').map(item => item.value)
}
const params = {
areas: techDomains.length > 0 ? techDomains.join(',') : undefined,
years: years.length > 0 ? years.join(',') : undefined,
keywords: undefined,
countries: countries,
sortOrder: value.value,
sortField: 'date',
currentPage: currentPageACTA.value,
pageSize: pageSizeACTA.value
};
try {
console.log('-----getACTAList params', params)
const res = await getACTAList(params);
console.log('-----getACTAList res', res)
if (res.code === 200) {
console.log('-----getACTAListInfo', res.data)
unionDataList.value = res.data.content
totalACTA.value = res.data.numberOfElements
}
} catch (error) {
console.error("获取规则限制政令列表查询接口接口失败:", error);
}
}
const getCompose = (item) => {
if (item) {
const countries = item.countries.map(i => i.COUNTRYNAME)
return item.ACTAYEAR + '年成立 · ' + countries.join('、')
}
}
watch(value, () => {
if (isShow.value) {
getRuleLimitListApi()
} else {
getACTAListInfo()
}
})
const getDate = (item) => {
if (item && item.PUBLISHDATE) {
let year = item.PUBLISHDATE.split('-')[0]
let month = item.PUBLISHDATE.split('-')[1]
let day = +item.PUBLISHDATE.split('-')[2]
return year + '年' + month + '月' + day + '日'
}
}
onMounted(async () => {
await getRuleLimitListApi()
try {
const res = await getAcTAAllcountry();
console.log('-----getAcTAAllcountry res', res)
if (res.code === 200) {
console.log('-----getAcTAAllcountry', res.data)
}
} catch (error) {
console.error("获取规则限制政令列表查询接口接口失败:", error);
}
})
const total = ref(1205);
const pageSize = ref(121);
const currentPage = ref(5);
const pageSize = ref(10);
const currentPage = ref(0);
const totalACTA = ref(1205);
const pageSizeACTA = ref(10);
const currentPageACTA = ref(0);
const handlePageChange = p => {
currentPage.value = p;
currentPage.value = p;
};
const handlePageChangeACTA = p => {
currentPageACTA.value = p;
};
</script>
......@@ -599,11 +578,23 @@ const handlePageChange = p => {
}
.left-content {
width: 253px;
height: 132px;
// height: 132px;
height: auto;
margin-left: 25px;
margin-top: 13px;
display: flex;
flex-wrap: wrap;
.el-checkbox {
width: 50%;
margin-right: 0;
margin-bottom: 4px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
color: rgb(95, 101, 108);
}
.left-item {
width: 120px;
height: 30px;
......@@ -736,15 +727,15 @@ const handlePageChange = p => {
cursor: pointer;
}
.type {
position: absolute;
top: 0;
right: 0;
padding: 2px 8px;
border-radius: 20px;
font-size: 16px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 24px;
position: absolute;
top: 0px;
right: 0px;
}
.type1 {
background-color: rgba(232, 189, 11, 0.1);
......@@ -780,7 +771,7 @@ const handlePageChange = p => {
height: 1150px;
border: 2px solid rgb(235, 238, 242);
position: absolute;
top: 75px;
top: 55px;
left: 120px;
z-index: 1;
}
......@@ -901,7 +892,7 @@ const handlePageChange = p => {
}
.left-content {
width: 253px;
height: 132px;
// height: 132px;
margin-left: 25px;
margin-top: 13px;
display: flex;
......@@ -947,7 +938,7 @@ const handlePageChange = p => {
margin-top: 21px;
}
.cl2 {
margin-top: 58px;
// margin-top: 58px;
}
}
.right-unshow {
......@@ -975,22 +966,19 @@ const handlePageChange = p => {
position: relative;
border-bottom: 1px solid rgb(234, 236, 238);
margin-bottom: 12px;
img {
width: 52px;
height: 52px;
margin-right: 16px;
.img-list {
width: 60px;
height: 46px;
overflow: hidden;
text-align: center;
.img-style {
width: 22px;
height: 22px;
border-radius: 50%;
}
}
.type {
position: absolute;
top: 0;
right: 0;
border-radius: 4px;
border: 1px solid;
padding: 2px 8px;
font-size: 14px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 20px;
display: flex;
}
.name {
font-size: 20px;
......@@ -1020,6 +1008,15 @@ const handlePageChange = p => {
border-color: rgba(145, 202, 255, 1);
color: rgba(22, 119, 255, 1);
background-color: rgba(230, 244, 255, 1);
border-radius: 4px;
border: 1px solid;
padding: 2px 8px;
font-size: 14px;
font-weight: 400;
width: auto;
font-family: "Microsoft YaHei";
line-height: 20px;
margin-right: 4px;
}
.type2 {
border-color: rgba(255, 163, 158, 1);
......@@ -1028,6 +1025,13 @@ const handlePageChange = p => {
}
.type3 {
border: none;
border-radius: 4px;
border: 1px solid;
padding: 2px 8px;
font-size: 14px;
font-weight: 400;
font-family: "Microsoft YaHei";
line-height: 20px;
}
}
.content {
......
......@@ -2,73 +2,92 @@
<div class="cooperation-restrictions-detail">
<div class="nav">
<div class="nav-main">
<img src="./assets/image01.png" alt="" />
<img src="./assets/image01.png" alt />
<div class="content">
<div class="cl1">美国联邦通信委员会(FCC)启动程序撤销对 TUV/宁波的认可</div>
<div class="cl2">FCC Begins Proceedings to Withdraw Recognition of TUV/Ningbo</div>
<div class="cl3">2025年10月24日 10:33 · 美国联邦通信委员会</div>
</div>
<div class="btn">
<button class="btn1"><img src="./assets/icon01.png" alt="" />查看原文</button>
<button class="btn1">
<img src="./assets/icon01.png" alt />查看原文
</button>
<!-- <button class="btn1"><img src="./assets/icon02.png" alt="" />查看官网</button> -->
<button class="btn1 active"><img src="./assets/icon03.png" alt="" />分析报告</button>
<button class="btn1 active">
<img src="./assets/icon03.png" alt />分析报告
</button>
</div>
</div>
</div>
<div class="title">
<span class="title-one">当前合作限制数据已关联至行政令:</span>
<span class="title-two">《美国联邦通信委员会(FCC)启动程序撤销对 TUV/宁波的认可》2025年10月24日</span>
<img src="./assets/right.png" alt="" />
<img src="./assets/right.png" alt />
</div>
<div class="main">
<div class="left">
<!-- 制裁概况 -->
<div class="left-top">
<img class="img1" src="./assets/bluetitle.png" alt="" />
<img class="img1" src="./assets/bluetitle.png" alt />
<div class="left-top-title">制裁概况</div>
<img class="img2" src="./assets/下载按钮.png" alt="" />
<img class="img3" src="./assets/收藏按钮.png" alt="" />
<img class="img2" src="./assets/下载按钮.png" alt />
<img class="img3" src="./assets/收藏按钮.png" alt />
<div class="left-top-content">
<span
>美国联邦通信委员会(FCC)启动程序撤销对德国莱茵 TÜV
集团/中国检验认证集团(宁波)有限公司作为测试认可实验室的认证。</span
>
<span>
美国联邦通信委员会(FCC)启动程序撤销对德国莱茵 TÜV
集团/中国检验认证集团(宁波)有限公司作为测试认可实验室的认证。
</span>
</div>
<div class="left-top-bottom">
<div><span class="tit">限制时间:</span><span class="tit1">2025年10月24日</span></div>
<div><span class="tit">限制机构:</span><span class="tit1 tit2">美国联邦通信委员会(FCC) ></span></div>
<div><span class="tit">限制手段:</span><span class="tit1">行政令</span></div>
<div><span class="tit">限制领域:</span><span class="tit3">集成电路</span></div>
<div>
<span class="tit">限制时间:</span>
<span class="tit1">2025年10月24日</span>
</div>
<div>
<span class="tit">限制机构:</span>
<span class="tit1 tit2">美国联邦通信委员会(FCC) ></span>
</div>
<div>
<span class="tit">限制手段:</span>
<span class="tit1">行政令</span>
</div>
<div>
<span class="tit">限制领域:</span>
<span class="tit3">集成电路</span>
</div>
</div>
</div>
<!-- 受限实体 -->
<div class="left-bottom">
<img class="img1" src="./assets/bluetitle.png" alt="" />
<img class="img1" src="./assets/bluetitle.png" alt />
<div class="left-bottom-title">受限实体</div>
<img class="img2" src="./assets/下载按钮.png" alt="" />
<img class="img3" src="./assets/收藏按钮.png" alt="" />
<img class="img2" src="./assets/下载按钮.png" alt />
<img class="img3" src="./assets/收藏按钮.png" alt />
<div class="left-bottom-main">
<div v-for="item in dataList" :key="item.id" class="main-box">
<img :src="item.img" alt="" />
<img :src="item.img" alt />
<div class="name">{{ item.name }}</div>
<div class="type">{{ item.type }}</div>
</div>
<img src="./assets/注意.png" alt="" />
<img src="./assets/注意.png" alt />
</div>
</div>
<!-- 规则限制事件脉络 -->
<div class="left-bottom-B">
<img class="img1" src="./assets/bluetitle.png" alt="" />
<img class="img1" src="./assets/bluetitle.png" alt />
<div class="left-bottom-title">规则限制事件脉络</div>
<img class="img2" src="./assets/下载按钮.png" alt="" />
<img class="img3" src="./assets/收藏按钮.png" alt="" />
<img class="img2" src="./assets/下载按钮.png" alt />
<img class="img3" src="./assets/收藏按钮.png" alt />
<div class="left-bottom-main">
<div v-for="item in objList" :key="item.id" class="main-box">
<img :src="item.img" alt="" />
<img :src="item.img" alt />
<div class="time">{{ item.time }}</div>
<div class="name">{{ item.name }}</div>
</div>
<div class="btn">查看更多 <img src="./assets/doubleLine.png" alt="" /></div>
<div class="btn">
查看更多
<img src="./assets/doubleLine.png" alt />
</div>
<div class="line"></div>
</div>
</div>
......@@ -76,21 +95,21 @@
<div class="right">
<!-- 背景分析 -->
<div class="right-bottom">
<img class="img1" src="./assets/bluetitle.png" alt="" />
<img class="img1" src="./assets/bluetitle.png" alt />
<div class="right-bottom-title">背景分析</div>
<div class="right-bottom-content1">
<div class="right-bottom-content1-title">
<span>(一)法律框架 </span>
<img src="./assets/打开按钮.png" alt="" />
</div>
<div class="right-bottom-content1-content">
《法案》第302条授权联邦通信委员会(以下简称委员会或FCC)制定符合公共利益的规则,管理能够发射射频(RF)能量设备的干扰潜力。该法案还允许委员会授权私人机构(测试实验室)进行符合这些规则的合规性测试,并为这些测试实验室建立适当的资质和标准。委员会不会认可未能满足所有适当标准的任何测试实验室,包括与测试实验室的诚信和可靠性相关的标准。委员会的规则部分规定,“确保参与FCC设备授权计划的测试实验室不受对国家安全构成风险的不可信行为者的所有权、指挥或控制。”
<span>(一)法律框架</span>
<img src="./assets/打开按钮.png" alt />
</div>
<div
class="right-bottom-content1-content"
>《法案》第302条授权联邦通信委员会(以下简称委员会或FCC)制定符合公共利益的规则,管理能够发射射频(RF)能量设备的干扰潜力。该法案还允许委员会授权私人机构(测试实验室)进行符合这些规则的合规性测试,并为这些测试实验室建立适当的资质和标准。委员会不会认可未能满足所有适当标准的任何测试实验室,包括与测试实验室的诚信和可靠性相关的标准。委员会的规则部分规定,“确保参与FCC设备授权计划的测试实验室不受对国家安全构成风险的不可信行为者的所有权、指挥或控制。”</div>
</div>
<div class="right-bottom-content2">
<div class="right-bottom-content2-title">
<span>(二)事实背景 </span>
<img src="./assets/打开按钮.png" alt="" />
<span>(二)事实背景</span>
<img src="./assets/打开按钮.png" alt />
</div>
<div class="right-bottom-content2-content">
TUV/宁波是一家位于中国浙江宁波的认可测试实验室,被FCC认可可对各种射频设备进行测试,以确保符合适用的FCC规则。根据美国实验室认可协会(A2LA)的信息,TUV/宁波的认证表明该实验室已按照公认的国际标准ISO/IEC
......@@ -99,8 +118,8 @@
</div>
<div class="right-bottom-content3">
<div class="right-bottom-content3-title">
<span>(二)其他背景 </span>
<img src="./assets/打开按钮.png" alt="" />
<span>(二)其他背景</span>
<img src="./assets/打开按钮.png" alt />
</div>
<div class="right-bottom-content3-content">
中华人民共和国(PRC)是一个禁止实体,根据委员会规则第2.902条的规定进行识别。OET 已初步确定
......@@ -116,28 +135,29 @@
</div>
<!-- 限制条款 -->
<div class="right-top">
<img class="img1" src="./assets/bluetitle.png" alt="" />
<img class="img1" src="./assets/bluetitle.png" alt />
<div class="right-top-title">限制条款</div>
<div class="right-top-content">
<div v-for="item in dataList2" :key="item.id" class="right-top-item">
<span class="id">{{ item.id }}</span>
<span class="name">{{ item.name }}</span>
<img src="./assets/打开按钮.png" alt="" />
<img src="./assets/打开按钮.png" alt />
</div>
</div>
</div>
<!-- 相关举措 -->
<div class="right-top-b">
<img class="img1" src="./assets/bluetitle.png" alt="" />
<img class="img1" src="./assets/bluetitle.png" alt />
<div class="right-top-title">相关举措</div>
<div class="right-top-content">
<div v-for="item in dataList3" :key="item.id" class="right-top-item">
<img :src="item.img" alt="" />
<img :src="item.img" alt />
<div class="name">{{ item.name }}</div>
<div class="time">{{ item.time }}</div>
<div class="type" :class="{ type1: item.type === '行政令', type2: item.type === '法案' }">
{{ item.type }}
</div>
<div
class="type"
:class="{ type1: item.type === '行政令', type2: item.type === '法案' }"
>{{ item.type }}</div>
<div class="content">{{ item.content }}</div>
</div>
</div>
......@@ -159,106 +179,118 @@ import czb from "./assets/财政部.png";
import gh from "./assets/国会.png";
const dataList = ref([
{
id: 1,
name: "中国检验认证集团(宁波)有限公司",
type: "",
img: ningbo
},
{
id: 2,
name: "德国莱茵 TÜV 集团",
type: "",
img: deguo
}
{
id: 1,
name: "中国检验认证集团(宁波)有限公司",
type: "",
img: ningbo
},
{
id: 2,
name: "德国莱茵 TÜV 集团",
type: "",
img: deguo
}
]);
const objList = ref([
{
id: 1,
name: "撤销多家中国实验室对进入美国市场电子产品的测试认证许可。",
time: "2025-08-30",
img: cycle
},
{
id: 2,
name: "禁止被认定存在“国家安全风险”的中国实验室为进入美国市场的电子设备(如手机、电脑)提供FCC要求的合规性测试与认...",
time: "2025-08-30",
img: cycle
},
{
id: 3,
name: "禁止授权进口或销售任何新设备。新规进一步禁止新设备中使用这些清单内公司的零部件,并允许FCC撤销已授权设备的许可。",
time: "2025-08-30",
img: cycle
},
{
id: 4,
name: "撤销或终止中国电信运营商在美国提供国际电信服务的授权。",
time: "2025-08-30",
img: cycle
},
{
id: 5,
name: "禁止使用特定中国技术和设备的公司建造或运营连接美国的通信电缆。",
time: "2025-08-30",
img: cycle
}
{
id: 1,
name: "撤销多家中国实验室对进入美国市场电子产品的测试认证许可。",
time: "2025-08-30",
img: cycle
},
{
id: 2,
name: "禁止被认定存在“国家安全风险”的中国实验室为进入美国市场的电子设备(如手机、电脑)提供FCC要求的合规性测试与认...",
time: "2025-08-30",
img: cycle
},
{
id: 3,
name: "禁止授权进口或销售任何新设备。新规进一步禁止新设备中使用这些清单内公司的零部件,并允许FCC撤销已授权设备的许可。",
time: "2025-08-30",
img: cycle
},
{
id: 4,
name: "撤销或终止中国电信运营商在美国提供国际电信服务的授权。",
time: "2025-08-30",
img: cycle
},
{
id: 5,
name: "禁止使用特定中国技术和设备的公司建造或运营连接美国的通信电缆。",
time: "2025-08-30",
img: cycle
}
]);
const dataList2 = ref([
{
id: 1,
name: "根据本命令,OET认定TUV/宁波没有说明委员会为何不应开始撤销其作为认可测试实验室资格的程序。在其回应中,TUV/宁波声称其不受委员会规则下的禁止实体控制或指挥,但未说明其被禁止实体持有的股权。TUV/宁波的公司治理文件显示,CCIC是公司的股东,并出资占公司创立资本的49%."
},
{
id: 2,
name: "TUV/宁波必须在本命令发布后三十五(35)天内提交回复,说明委员会为何不应撤销其认可。如果未能及时回复或提交说明委员会不应撤销其认可的合理依据的回复,可能会导致撤销认可。公司的回复必须包含一份书面详细事实说明,充分说明公司是否由中华人民共和国拥有、控制或受其指示。"
},
{
id: 3,
name: "OET 根据《法案》第302(e)条以及委员会规则第2.951(d)和(e)条启动了一个程序,以最终确定是否撤销对TUV/Ningbo作为认可测试实验室的认可。此程序为公司提供了额外的通知和机会,以提交书面回应,说明委员会为何不应撤销其当前的认可。"
}
{
id: 1,
name: "根据本命令,OET认定TUV/宁波没有说明委员会为何不应开始撤销其作为认可测试实验室资格的程序。在其回应中,TUV/宁波声称其不受委员会规则下的禁止实体控制或指挥,但未说明其被禁止实体持有的股权。TUV/宁波的公司治理文件显示,CCIC是公司的股东,并出资占公司创立资本的49%."
},
{
id: 2,
name: "TUV/宁波必须在本命令发布后三十五(35)天内提交回复,说明委员会为何不应撤销其认可。如果未能及时回复或提交说明委员会不应撤销其认可的合理依据的回复,可能会导致撤销认可。公司的回复必须包含一份书面详细事实说明,充分说明公司是否由中华人民共和国拥有、控制或受其指示。"
},
{
id: 3,
name: "OET 根据《法案》第302(e)条以及委员会规则第2.951(d)和(e)条启动了一个程序,以最终确定是否撤销对TUV/Ningbo作为认可测试实验室的认可。此程序为公司提供了额外的通知和机会,以提交书面回应,说明委员会为何不应撤销其当前的认可。"
}
]);
const dataList3 = ref([
{
id: 1,
name: "美国商务部工业与安全局发布实体清单,涉及多家中国半导体企业",
time: "2025年9月12日",
content:
"23家中国实体,包括复旦微电旗下多家公司、华岭股份等,指控这些实体“违背美国国家安全或外交政策利益”,包括为中国的...",
type: "行政令",
img: swb
},
{
id: 2,
name: "美国白宫发布总统政令,提出将发展美国人工智能产业硬件支持放在新任期的科技首要地位",
time: "2025年9月11日",
content:
"9个中国实体​(8家企业和1名个人),例如湖北奇卡工业有限公司、广州雅凯国际货运代理有限公司等,指控这些实体为也门胡塞...",
type: "行政令",
img: bg
},
{
id: 3,
name: "美国财政部外国资产控制办公室指控中国企业及船只",
time: "2025年3月13日",
content:
"​4家中国企业和3艘关联船只​(如香港和顺运贸有限公司、华夏贸易有限公司等),指控这些公司拥有或运营向中国运送伊朗石油或...",
type: "行政令",
img: czb
},
{
id: 4,
name: "美国国会通过《芯片科学》法案",
time: "2025年1月3日",
content:
"​多家中国实体,包括成都雷电微力科技股份有限公司、中国科学院长春光学精密机械与物理研究所等,指控这些实体与中国高超音...",
type: "法案",
img: gh
}
{
id: 1,
name: "美国商务部工业与安全局发布实体清单,涉及多家中国半导体企业",
time: "2025年9月12日",
content:
"23家中国实体,包括复旦微电旗下多家公司、华岭股份等,指控这些实体“违背美国国家安全或外交政策利益”,包括为中国的...",
type: "行政令",
img: swb
},
{
id: 2,
name: "美国白宫发布总统政令,提出将发展美国人工智能产业硬件支持放在新任期的科技首要地位",
time: "2025年9月11日",
content:
"9个中国实体​(8家企业和1名个人),例如湖北奇卡工业有限公司、广州雅凯国际货运代理有限公司等,指控这些实体为也门胡塞...",
type: "行政令",
img: bg
},
{
id: 3,
name: "美国财政部外国资产控制办公室指控中国企业及船只",
time: "2025年3月13日",
content:
"​4家中国企业和3艘关联船只​(如香港和顺运贸有限公司、华夏贸易有限公司等),指控这些公司拥有或运营向中国运送伊朗石油或...",
type: "行政令",
img: czb
},
{
id: 4,
name: "美国国会通过《芯片科学》法案",
time: "2025年1月3日",
content:
"​多家中国实体,包括成都雷电微力科技股份有限公司、中国科学院长春光学精密机械与物理研究所等,指控这些实体与中国高超音...",
type: "法案",
img: gh
}
]);
const overviewInfo = ref({})
// const getUrlParams = () => {
// const urlParams = new URLSearchParams(window.location.search);
// sanRecordId.value = urlParams.get("id") || ""
// }
onMounted(() => {
// getUrlParams()
})
</script>
<style lang="scss" scoped>
......
......@@ -6,7 +6,7 @@
<input v-model="input" class="search-input" placeholder="搜索规则限制" />
<div class="search-btn-small" @click="handleSearch">
<div class="search-icon">
<img src="./assets/icons/search-icon.png" alt="" />
<img src="./assets/icons/search-icon.png" alt />
</div>
<div class="search-text">搜索</div>
</div>
......@@ -15,25 +15,25 @@
<div class="btn" @click="handleToPosi('position1')">
<div class="btn-text">最新动态</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
<div class="btn" @click="handleToPosi('position2')">
<div class="btn-text">咨询要闻</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
<div class="btn" @click="handleToPosi('position3')">
<div class="btn-text">数据总览</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
<div class="btn" @click="handleToPosi('position4')">
<div class="btn-text">资源库</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
</div>
......@@ -55,51 +55,51 @@
<div class="search-main">
<input v-model="input" placeholder="搜索规则限制" class="search-input" />
<div class="search-btn">
<img src="./assets/icons/search-icon.png" alt="" />
<img src="./assets/icons/search-icon.png" alt />
搜索
</div>
</div>
<!-- <div class="search-center">
<div class="search-center">
<div class="search-item">
<div class="search-item-num">190</div>
<div class="search-item-num">{{ statCountInfo.AOCOUNT }}</div>
<div class="search-item-name">规则限制政令</div>
</div>
<div class="search-item">
<div class="search-item-num">125</div>
<div class="search-item-num">{{ statCountInfo.ENTITYCOUNT }}</div>
<div class="search-item-name">规则限制实体</div>
</div>
<div class="search-item">
<div class="search-item-num">18</div>
<div class="search-item-num">{{ statCountInfo.ACTACOUNT }}</div>
<div class="search-item-name">排华科技联盟</div>
</div>
<div class="search-item">
<div class="search-item-num">12</div>
<div class="search-item-num">{{ statCountInfo.COUNTRYCOUNT }}</div>
<div class="search-item-name">排华国家数量</div>
</div>
</div> -->
</div>
<div class="search-bottom">
<div class="btn" @click="handleToPosi('position1')">
<div class="btn-text">最新动态</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
<div class="btn" @click="handleToPosi('position2')">
<div class="btn-text">咨询要闻</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
<div class="btn" @click="handleToPosi('position3')">
<div class="btn-text">数据总览</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
<div class="btn" @click="handleToPosi('position4')">
<div class="btn-text">资源库</div>
<div class="btn-icon">
<img src="@/assets/icons/arrow-right-icon.png" alt="" />
<img src="@/assets/icons/arrow-right-icon.png" alt />
</div>
</div>
</div>
......@@ -137,7 +137,7 @@
</template>
<script setup>
import { ref, nextTick } from "vue";
import { ref, nextTick, onMounted } from "vue";
import { useRouter } from "vue-router";
import comTitle from "./common/comTitle.vue";
import newData from "./components/dataNew/index.vue";
......@@ -147,6 +147,7 @@ import resLib from "./components/resLib/index.vue";
import HeaderMenu from "@/components/headerMenu.vue";
import headerInfo from "@/components/headerInfo.vue";
import { useContainerScroll } from "@/hooks/useScrollShow";
import { getStatCount } from '@/api/ruleRestriction/index.js'
// 搜索框
const input = ref("");
......@@ -155,35 +156,59 @@ const { isShow } = useContainerScroll(homeMainRef);
const router = useRouter();
const statCountInfo = ref({})
const getStatCountInfo = async () => {
try {
const res = await getStatCount();
if (res && res.code === 200) {
// console.log('----getStatCountInfo', res.data)
statCountInfo.value = res.data
}
} catch (error) {
console.error("获取首页统计接口失败:", error);
}
}
// 搜索功能
const handleSearch = () => {
console.log("搜索内容:", input.value);
console.log("搜索内容:", input.value);
};
// 锚点跳转
const handleToPosi = id => {
const element = document.getElementById(id);
if (element && homeMainRef.value) {
// 如果当前还未显示吸顶搜索栏,先强制切换状态以稳定布局
if (!isShow.value) {
isShow.value = true;
}
const element = document.getElementById(id);
if (element && homeMainRef.value) {
// 如果当前还未显示吸顶搜索栏,先强制切换状态以稳定布局
if (!isShow.value) {
isShow.value = true;
}
// 使用 nextTick 确保 DOM 状态更新(高度变化生效)后再计算
nextTick(() => {
const containerRect = homeMainRef.value.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
// 使用 getBoundingClientRect 计算元素相对于容器顶部的绝对距离,不受嵌套布局影响
const top = elementRect.top - containerRect.top + homeMainRef.value.scrollTop;
// 使用 nextTick 确保 DOM 状态更新(高度变化生效)后再计算
nextTick(() => {
const containerRect = homeMainRef.value.getBoundingClientRect();
const elementRect = element.getBoundingClientRect();
// 使用 getBoundingClientRect 计算元素相对于容器顶部的绝对距离,不受嵌套布局影响
const top = elementRect.top - containerRect.top + homeMainRef.value.scrollTop;
homeMainRef.value.scrollTo({
top: top,
behavior: "smooth"
});
});
}
homeMainRef.value.scrollTo({
top: top,
behavior: "smooth"
});
});
}
};
// 返回首页
const handleBackHome = () => {
router.push({
path: "/overview"
});
};
onMounted(async () => {
await getStatCountInfo()
})
</script>
<style scoped lang="scss">
......@@ -220,6 +245,45 @@ const handleToPosi = id => {
width: 960px;
height: 168px;
margin: 0 auto 68px auto;
.search-center {
width: 688px;
height: 48px;
margin: 0 auto;
margin-top: 36px;
display: flex;
justify-content: space-between;
.search-item {
width: 120px;
height: 57px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
.search-item-num {
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 36px;
font-weight: 700;
line-height: 22px;
letter-spacing: 0px;
text-align: center;
color: rgba(5, 95, 194, 1);
}
.search-item-name {
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: center;
color: rgba(95, 101, 108, 1);
}
}
}
.search-main {
display: flex;
padding-right: 3px;
......
......@@ -2,24 +2,31 @@
<template>
<div class="source-library-container">
<div class="source-library-grid">
<div v-for="(item, index) in PersonResource" :key="index" class="source-library-card" @click="handleClcikToCharacter(item.id)">
<div
v-for="(item, index) in PersonResource"
:key="index"
class="source-library-card"
@click="handleClcikToCharacter(item.id)"
>
<div class="source-library-avatar-wrapper">
<img :src="item.avatar" alt="" class="source-library-avatar" />
</div>
<div class="source-library-text-content">
<div style="width: 240px;height: 120px;display: flex; flex-direction: column;">
<div style="width: 240px; height: 120px; display: flex; flex-direction: column">
<h3 class="source-library-name">{{ item.name }}</h3>
<p class="source-library-title">{{ item.title }}</p>
<div class="taglist">
<p
class="source-library-tag"
v-for="value in item.tag"
:class="{tag1: value.typeId === '001',
v-for="(value, index) in item.tag"
:key="index"
:class="{
tag1: value.typeId === '001',
tag2: value.typeId === '002',
tag3: value.typeId === '003',
tag4: value.typeId === '004',
tag5: value.typeId === '005',
tag6: value.typeId === '006',
tag6: value.typeId === '006'
}"
>
{{ value.typeName }}
......@@ -30,7 +37,7 @@
</div>
</div>
<div class="page">
<div class="count">{{ `共 ${total} 项`}}</div>
<div class="count">{{ `共 ${total} 项` }}</div>
<el-pagination
@current-change="handleCurrentChange"
:page-size="pageSize"
......@@ -46,25 +53,26 @@
<script setup>
// 导入数据(建议使用更具语义的变量名)
import sourceLibraryData from "../json/source.json";
import { ref,onMounted,defineProps,watch } from "vue";
import { ref, onMounted, watch } from "vue";
import { useRouter } from "vue-router";
import DefaultIcon1 from '@/assets/icons/default-icon1.png'
import DefaultIcon2 from '@/assets/icons/default-icon2.png'
import DefaultIcon1 from "@/assets/icons/default-icon1.png";
import DefaultIcon2 from "@/assets/icons/default-icon2.png";
import {getPersonResource,getPersonSummaryInfo } from "@/api/technologyFigures/technologyFigures";
import { getPersonResource, getPersonSummaryInfo } from "@/api/technologyFigures/technologyFigures";
const props = defineProps({
typeId: {
type: String,
default: "000"
}
typeId: {
type: String,
default: "000"
}
});
watch(() => props.typeId, (val) => {
handlegetPersonResourceFn();
})
watch(
() => props.typeId,
val => {
handlegetPersonResourceFn();
}
);
const router = useRouter();
......@@ -88,11 +96,11 @@ const handlegetPersonResourceFn = async () => {
currentPage: currentPage.value - 1, // Standard Spring Boot page index is 0-based
pageSize: pageSize.value
};
if(props.typeId !== '000'){
if (props.typeId !== "000") {
params.personTypeId = props.typeId;
}
try {
const res = await getPersonResource(params,abortController.value.signal);
const res = await getPersonResource(params, abortController.value.signal);
console.log("人物资源库", res);
if (res.code === 200) {
if (res.data && res.data.content) {
......@@ -104,7 +112,6 @@ const handlegetPersonResourceFn = async () => {
avatar: item.personImage || DefaultIcon1
}));
total.value = res.data.totalElements;
} else {
PersonResource.value = [];
total.value = 0;
......@@ -129,7 +136,7 @@ const handleCurrentChange = page => {
};
// 跳转人物主页
const handleClcikToCharacter = async (id) => {
const handleClcikToCharacter = async id => {
const personTypeList = JSON.parse(window.sessionStorage.getItem("personTypeList"));
let type = 0;
......@@ -183,13 +190,9 @@ const handleClcikToCharacter = async (id) => {
};
onMounted(async () => {
handlegetPersonResourceFn();
handlegetPersonResourceFn();
});
const handlePageChange = p => {
currentPage.value = p;
};
......@@ -219,7 +222,6 @@ const handlePageChange = p => {
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
cursor: pointer;
}
.source-library-card:hover {
......@@ -232,25 +234,25 @@ const handlePageChange = p => {
}
.person-tags {
display: flex;
margin-top: -20px;
width: 42px;
padding-left: 28px;
text-align: center;
display: flex;
margin-top: -20px;
width: 42px;
padding-left: 28px;
text-align: center;
}
.person-tag-bg {
/* 椭圆 6 */
width: 32px;
height: 32px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
/* 椭圆 6 */
width: 32px;
height: 32px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
}
.tag-icon {
width: 24px;
height: 24px;
object-fit: contain;
width: 24px;
height: 24px;
object-fit: contain;
}
.source-library-avatar {
......@@ -263,7 +265,6 @@ const handlePageChange = p => {
.source-library-text-content {
width: 656px;
flex: 1;
}
.source-library-name {
......@@ -290,7 +291,7 @@ const handlePageChange = p => {
text-align: left;
}
.taglist{
.taglist {
display: flex;
gap: 10px;
margin-top: auto;
......
......@@ -129,6 +129,7 @@ import {
getThinkTankReportIndustry,
getThinkTankReportIndustryCloud
} from "@/api/thinkTank/overview";
import {getChartAnalysis} from '@/api/aiAnalysis/index'
import { useRouter } from "vue-router";
const router = useRouter();
......@@ -256,118 +257,6 @@ const majorOpinions = ref([
status: 2
}
]
},
{
id: 3,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "半导体",
status: 4
}
]
},
{
id: 4,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "关税",
status: 2
},
{
name: "跨境电商",
status: 1
}
]
},
{
id: 5,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "关税",
status: 2
},
{
name: "跨境电商",
status: 1
}
]
},
{
id: 6,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "关税",
status: 2
},
{
name: "跨境电商",
status: 1
}
]
},
{
id: 7,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "产业脱钩",
status: 6
}
]
},
{
id: 8,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "关税",
status: 2
},
{
name: "跨境电商",
status: 1
}
]
},
{
id: 9,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "关税",
status: 2
},
{
name: "跨境电商",
status: 1
}
]
},
{
id: 10,
title: "我是示例标题",
desc: "我是示例内容",
tagList: [
{
name: "关税",
status: 2
},
{
name: "跨境电商",
status: 1
}
]
}
]);
// 处理页码改变事件
......@@ -384,12 +273,25 @@ const handleGetThinkTankReportContent = async () => {
console.log("主要观点", res.data);
if (res.code === 200 && res.data) {
majorOpinions.value = res.data.content;
handleGetBox3AnalysisContent(majorOpinions.value)
total.value = res.data.totalElements
}
} catch (error) {
console.error("获取主要观点error", error);
}
};
// 获取图表分析内容
const box3AnalysisContent = ref('')
const handleGetBox3AnalysisContent = async (textJson) => {
const params = {
text: textJson
}
const res = await getChartAnalysis(params)
console.log('图表解析内容', res);
}
onMounted(() => {
handleGetThinkTankReportAbstract();
handleGetThinkTankReportContent();
......
......@@ -75,6 +75,11 @@ export default defineConfig({
target: 'http://106.12.150.59:18826/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/temporarySearch/, '')
},
'/aiAnalysis': {
target: 'http://8.140.26.4:15000/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/temporarySearch/, '')
}
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论