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

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

# Conflicts: # src/views/thinkTank/index.vue
......@@ -140,3 +140,16 @@ export function getBillHyly(params) {
params,
})
}
// 根据法案ID获取法案全局信息
/**
* @param {id}
* @header token
*/
export function getBillInfoGlobal(params) {
return request({
method: 'GET',
url: `/api/billInfoBean/summary/${params.id}`,
params,
})
}
\ No newline at end of file
......@@ -328,6 +328,49 @@ export function getSelectEntitiesList(startTime) {
);
}
/**
* 涉及50%规则的实体数
*/
export function getEntitiesCountBy50PercentRules(
typeName = "实体清单",
pageNum = 1,
pageSize = 10,
sanctionDate = "",
isCn = false
) {
return request200(
request({
method: "POST",
url: "/api/sanctionList/getRuleCount",
data: {
typeName,
pageNum,
pageSize,
sanctionDate,
isCn
}
})
);
}
/**
* 获取前序事件
*/
// /entitiesDataInfo/precedingEvents
export function getPrecedingEvents(startTime = "2025-11-11", pageNum = 1, pageSize = 10) {
return request200(
request({
method: "POST",
url: "/api/entitiesDataInfo/precedingEvents",
data: {
sanctionDate: startTime,
pageNum,
pageSize
}
})
);
}
/**
* 领域分布查询
*/
......@@ -352,7 +395,7 @@ export function getDomainDistribution(sanctionDate = "2025-11-11") {
* startTime: string
* }[]>}
*/
export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize = 10, sanctionDate = "", rule = false) {
export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize = 10, sanctionDate = "", isCn = false) {
return request200(
request({
method: "POST",
......@@ -362,7 +405,7 @@ export function getEntitiesList(typeName = "实体清单", pageNum = 1, pageSize
pageNum,
pageSize,
sanctionDate,
rule
isCn
}
})
);
......@@ -584,7 +627,8 @@ export function getCountThisType(param) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataCount/countThisType",
// url: "/api/entitiesDataCount/countThisType",
url: "/api/entitiesDataInfo/annual/researchInstitute",
params: {
param
}
......@@ -592,6 +636,48 @@ export function getCountThisType(param) {
);
}
/**
* 企业类实体历史制裁情况
*/
export function getEnterpriseSanCount() {
return request200(
request({
method: "GET",
url: "/api/entitiesDataInfo/annual/enterprise"
})
);
}
/**
* 根据领域获取产业链信息
*/
export function getChainInfoByDomainId(domainId) {
return request200(
request({
method: "GET",
url: "/api/chain/getChainInfo",
params: {
domainId
}
})
);
}
/**
* 产业链中国企业实体信息查询
*/
export function getCnEntityOnChain(chainId) {
return request200(
request({
method: "GET",
url: "/api/chain/getChainEntityStat",
params: {
chainId
}
})
);
}
/**
* 产业链信息查询
*/
......@@ -677,3 +763,76 @@ export function getKeyListedEntityList(date, keyword = "") {
})
);
}
/**
* 获取科学仪器对美依赖数量
*/
export function getScientificInstrumentDependencyCount(orgIds = "12100000400012916R,121000004013595328,12100000435230200R") {
return request200(
request({
method: "GET",
url: "/api/instrument/getDependencyUS",
params: {
orgIds
}
})
);
}
/**
* 科学仪器近十年对美依赖度升高风险分析
* url: /instrument/getDependencyUSRisk
*/
export function getScientificInstrumentDependencyRisk() {
return request200(
request({
method: "GET",
url: "/api/instrument/getDependencyUSRisk"
})
);
}
/**
* 科学仪器近十年国产化数量统计
* url:/instrument/getLocalizationRisk
*/
export function getScientificInstrumentLocalizationRisk() {
return request200(
request({
method: "GET",
url: "/api/instrument/getLocalizationRisk"
})
);
}
/**
* 科学仪器进口国统计
* url: /instrument/getOriginCount
*/
export function getScientificInstrumentOriginCount(orgIds = "12100000400012916R,121000004013595328,12100000435230200R") {
return request200(
request({
method: "GET",
url: "/api/instrument/getOriginCount",
params: {
orgIds
}
})
);
}
/**
* 新增科研机构列表
* url: /entitiesDataInfo/scientificImpact/entityList
*/
export function getScientificImpactEntityList(startTime) {
return request200(
request({
method: "GET",
url: "/api/entitiesDataInfo/scientificImpact/entityList",
params: {
sanctionDate: startTime || "2025-11-11"
}
})
);
}
......@@ -141,6 +141,7 @@ export function getThinkPolicy(params) {
return request({
method: 'GET',
url: `/api/thinkTankInfo/policy/${params.id}/${params.startDate}`,
params
})
}
......
......@@ -49,3 +49,27 @@
scrollbar-width: thin;
scrollbar-color: #c1c1c1 #f1f1f1;
}
/* 只针对水平滚动条 */
::-webkit-scrollbar:horizontal {
height: 5px;
}
/* 水平滚动条轨道 */
::-webkit-scrollbar-track:horizontal {
background: linear-gradient(90deg, #f0f0f0, #e0e0e0);
}
/* 水平滚动条滑块 */
::-webkit-scrollbar-thumb:horizontal {
background: #bcbcbc;
min-width: 40px; /* 最小宽度 */
}
::-webkit-scrollbar-thumb:horizontal:hover {
background: #505357;
}
::-webkit-scrollbar-thumb:horizontal:active {
background: #505357;
}
\ No newline at end of file
......@@ -6,12 +6,12 @@
<div class="layout-main-header-left-box">
<div class="left-box-top">
<div class="icon">
<img src="./assets/images/USA-logo.png" alt="" />
<img :src="billInfoGlobal.imageUrl || USALogo" alt="" />
</div>
<div class="info">
<div class="info-box1">{{ "H.R.1(119th)-大而美法案" }}</div>
<div class="info-box1">{{ billInfoGlobal.billName }}</div>
<div class="info-box2">
{{ "第119届美国国会众议院第1号法案 One Big Beautiful Bill Act" }}
{{ billInfoGlobal.description }} {{ billInfoGlobal.billNameEn }}
</div>
</div>
</div>
......@@ -35,8 +35,8 @@
</div>
<div class="layout-main-header-right-box">
<div class="right-box-top">
<div class="time">{{ "2025年7月" }}</div>
<div class="name">{{ "乔迪·阿灵顿(Jodey Arrington)​​ " }}</div>
<div class="time">{{ billInfoGlobal.introductionDate }}</div>
<div class="name">{{ billInfoGlobal.tarName }}</div>
</div>
<div class="right-box-bottom">
<!-- <el-button type="plain" size="large" icon="Search" @click="handleSwitchActiveName('法案原文')"
......@@ -135,6 +135,7 @@
<script setup>
import { ref, onMounted } from "vue";
import router from "@/router";
import { getBillInfoGlobal } from "@/api/bill";
import icon1 from "./assets/icons/icon1.png";
import icon1Active from "./assets/icons/icon1_active.png";
......@@ -144,9 +145,24 @@ import icon3 from "./assets/icons/icon3.png";
import icon3Active from "./assets/icons/icon3_active.png";
import icon4 from "./assets/icons/icon4.png";
import icon4Active from "./assets/icons/icon4_active.png";
import USALogo from "./assets/images/USA-logo.png";
const activeName = ref("分析报告");
// 获取法案全局信息
const billInfoGlobal = ref({});
const getBillInfoGlobalFn = async () => {
const res = await getBillInfoGlobal({
id: window.sessionStorage.getItem("billId")
});
if (res.code === 200) {
console.log("法案全局信息", res);
if (res.data) {
billInfoGlobal.value = res.data;
}
}
};
const handleSwitchActiveName = name => {
activeName.value = name;
};
......@@ -200,6 +216,7 @@ const handleClickMainHeaderBtn = item => {
};
onMounted(() => {
getBillInfoGlobalFn();
if (window.sessionStorage.getItem("activeTitle")) {
activeTitle.value = window.sessionStorage.getItem("activeTitle");
}
......@@ -377,7 +394,7 @@ onMounted(() => {
margin-left: 9px;
.info-box1 {
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-family: "Microsoft YaHei";
font-size: 20px;
font-weight: 600;
line-height: 22px;
......@@ -387,16 +404,20 @@ onMounted(() => {
}
.info-box2 {
margin-top: 5px;
height: 22px;
// height: 22px;
line-height: 22px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-family: "Microsoft YaHei";
font-size: 14px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: left;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
......
......@@ -1092,6 +1092,19 @@ onMounted(async () => {
.dialog-box1-main {
margin-top: 4px;
margin-left: 18px;
max-height: 120px;
overflow-y: auto;
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.2);
}
&::-webkit-scrollbar-track {
border-radius: 0;
background: rgba(0, 0, 0, 0.1);
}
.item {
display: flex;
.item-left {
......@@ -1107,13 +1120,16 @@ onMounted(async () => {
.item-right {
margin-top: 8px;
margin-left: 9px;
width: 420px;
width: 400px;
height: 22px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
......
......@@ -106,7 +106,7 @@
<div class="home-main-header-item-box">
<div class="item" v-for="(item, index) in govInsList" :key="index" @click="handleToInstitution(item)">
<div class="item-left">
<img :src="item.img?item.img: DefaultIcon2" alt="" />
<img :src="item.img ? item.img : DefaultIcon2" alt="" />
</div>
<div class="item-right">{{ item.name }}</div>
</div>
......@@ -116,16 +116,16 @@
<div class="home-main-center">
<div class="center-top">
<div class="box1">
<!-- <div class="box1-left">
<div class="box1-left" @click="handleSwithCurDecree('left')">
<div class="icon">
<img src="./assets/images/box1-left.png" alt="" />
</div>
</div>
<div class="box1-right">
<div class="box1-right" @click="handleSwithCurDecree('right')">
<div class="icon">
<img src="./assets/images/box1-right.png" alt="" />
</div>
</div> -->
</div>
<div class="box1-header">
<div class="box1-header-left">
<div class="icon">
......@@ -137,7 +137,14 @@
{{ "查看详情 >" }}
</div>
</div>
<el-carousel ref="carouselRef" trigger="click" height="395px" :autoplay="true">
<el-carousel
ref="carouselRef"
height="395px"
:autoplay="true"
:interval="3000"
arrow="never"
indicator-position="none"
>
<el-carousel-item v-for="(item, index) in box1DataList" :key="index">
<div class="box1-main">
<div class="box1-main-left">
......@@ -335,7 +342,6 @@
<DivideHeader id="position4" class="divide4" :titleText="'资源库'"></DivideHeader>
<div class="home-main-footer-header">
<div class="btn-box">
<div
class="btn"
:class="{ btnActive: activeCate === cate.id }"
......@@ -345,7 +351,6 @@
>
{{ cate.name }}
</div>
</div>
<div class="select-box">
<div class="paixu-btn" @click="handleSwithSort">
......@@ -375,6 +380,7 @@
:key="time.id"
v-model="activePubTime"
:label="time.id"
style="width: 100px"
class="filter-checkbox"
>
{{ time.name }}
......@@ -414,13 +420,13 @@
class="main-item"
v-for="(item, index) in curDecreeList"
:key="index"
@click="handleClickToDetail"
@click="handleClickDecree(item)"
>
<div class="main-item-left">
<div class="left-left">{{ item.time }}</div>
<div class="left-right">
<div class="icon">
<img :src="item.orgImage?item.orgImage:DefaultIcon2" alt="">
<img :src="item.orgImage ? item.orgImage : DefaultIcon2" alt="" />
</div>
<div class="line" v-if="index !== 9 && index !== totalDecreesNum - 1"></div>
</div>
......@@ -497,8 +503,8 @@ import getCalendarHeatChart from "./utils/cleandarHeat";
import setChart from "@/utils/setChart";
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 p1 from "./assets/images/iconp1.png";
import p2 from "./assets/images/iconp2.png";
......@@ -534,10 +540,8 @@ import Message3 from "./assets/images/message-icon3.png";
// 跳转行政机构主页
const handleToInstitution = item => {
if (item.name === "美国商务部") {
const curRoute = router.resolve("/institution");
window.open(curRoute.href, "_blank");
}
};
// 返回首页
......@@ -689,6 +693,17 @@ const handleClickToDetail = () => {
window.open(route.href, "_blank");
};
// 点击政令库政令
const handleClickDecree = decree => {
const route = router.resolve({
path: "/decreeLayout",
query: {
id: decree.id
}
});
window.open(route.href, "_blank");
};
// 风险信号
const warningList = ref([
{
......@@ -780,7 +795,6 @@ const messageList = ref([
// time: "14:49 · 发布于X",
// content: `如果这个疯狂的支出法案获得通过,‘美国党’将在第二天成立。`
// }
]);
const handleGetMessage = async () => {
const params = {
......@@ -854,7 +868,6 @@ const chart2Data = ref([
// name: "人工智能",
// value: 46
// },
]);
// const colorList = ["#69B1FF", "#FFC069", "#87E8DE", "#85A5FF", "#FF7875", "#B37FEB", "#4096FF"];
......@@ -892,7 +905,6 @@ const keyDecreeList = ref([
// time: "2025年2月",
// content: `将中国列为“外国对手”,系统性收紧中美在半导体、人工智能、量子技术等前沿科技领域的双向投资,构建对华科技封锁体系。`
// },
]);
const handleGetKeyDecree = async () => {
......@@ -1111,6 +1123,15 @@ watch(
}
);
// 切换当前政令
const handleSwithCurDecree = name => {
if (name === "left") {
carouselRef.value.prev();
} else {
carouselRef.value.next();
}
};
onMounted(async () => {
handleGetAreaList();
handleGetDecreeOrderList();
......@@ -1447,6 +1468,7 @@ onMounted(async () => {
position: relative;
.box1-left {
position: absolute;
z-index: 9999;
left: 0;
top: 200px;
width: 24px;
......@@ -1467,6 +1489,7 @@ onMounted(async () => {
}
.box1-right {
position: absolute;
z-index: 9999;
right: 0;
top: 200px;
width: 24px;
......@@ -1857,7 +1880,7 @@ onMounted(async () => {
height: 402px;
overflow-y: auto;
overflow-x: hidden;
padding-top: 6px;
padding: 6px 0;
.box3-item {
display: flex;
height: 77px;
......@@ -1967,7 +1990,7 @@ onMounted(async () => {
height: 402px;
overflow-y: auto;
box-sizing: border-box;
padding-top: 8px;
padding-bottom: 8px;
.box4-main-item {
margin-top: 16px;
display: flex;
......@@ -2601,7 +2624,8 @@ onMounted(async () => {
}
}
.box7-main {
height: 400px;
margin-top: 10px;
height: 380px;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
......@@ -2720,7 +2744,6 @@ onMounted(async () => {
width: 1600px;
height: 70px;
margin: 36px auto 16px;
// background: orange;
display: flex;
justify-content: space-between;
.btn-box {
......@@ -2731,6 +2754,7 @@ onMounted(async () => {
display: flex;
gap: 8px;
white-space: nowrap;
.btn {
min-width: min-content;
height: 42px;
......@@ -2756,7 +2780,6 @@ onMounted(async () => {
background: rgba(20, 89, 187, 1);
}
}
}
.select-box {
margin-top: 5px;
......@@ -2903,7 +2926,8 @@ onMounted(async () => {
gap: 18px;
justify-content: flex-end;
.left-left {
width: 84px;
margin-left: 30px;
width: 54px;
height: 48px;
color: var(--color-main-active);
font-family: Microsoft YaHei;
......@@ -2919,7 +2943,7 @@ onMounted(async () => {
height: 24px;
border-radius: 12px;
overflow: hidden;
img{
img {
width: 100%;
height: 100%;
}
......
[
{
"personImage": "https://www.congress.gov/img/member/y000064_200.jpg",
"personName": "扬(Young, Todd)",
"remarks": "拜登打心底里厌恶美国的石油和天然气产业,他的一系列政策,正在摧毁这个能为美国创造大量就业岗位的重要领域。",
"time": "2025-04-12T03:27:07",
"orgName": "推特"
"name": "美国",
"count": 0.37960339943342775
},
{
"personImage": "https://www.congress.gov/img/member/k000306_200.jpg",
"personName": "科尔贝 (Kolbe), 吉姆 (Jim)",
"remarks": "美国将控制加沙地带,我们会把这片被战火摧毁的区域改造成 “中东的里维埃拉”,这一计划会为当地带来全新未来。",
"time": "2025-01-12T00:55:53",
"orgName": "推特"
"name": "德国",
"count": 0.20113314447592068
},
{
"name": "日本",
"count": 0.1558073654390935
}
]
\ No newline at end of file
......@@ -2,7 +2,7 @@
<div class="fishbone-wrapper">
<div class="fishbone-scroll-container" ref="scrollContainerRef">
<div class="fishbone" ref="fishboneRef" v-if="fishboneData.length > 0">
<div class="main-line" :style="{ width: (fishboneData.length / 2) * 340 - 275 + 'px' }"></div>
<div class="main-line" :style="{ width: (fishboneData.length / 2) * 340 - 200 + 'px' }"></div>
<!-- 奇数索引的数据组放在上方 -->
<div
v-for="(causeGroup, groupIndex) in getOddGroups(fishboneData)"
......
......@@ -99,6 +99,13 @@ import college9 from "../../assets/images/college9.png";
import college10 from "../../assets/images/college10.png";
import college11 from "../../assets/images/college11.png";
import { getHorizontalBarChart1, getPieOption2, getMultipleLineChart } from "../../utils/charts";
import {
getScientificImpactEntityList,
getScientificInstrumentDependencyCount,
getScientificInstrumentDependencyRisk,
getScientificInstrumentLocalizationRisk,
getScientificInstrumentOriginCount
} from "@/api/exportControl";
const selectOptions = [
{
value: 1,
......@@ -170,39 +177,153 @@ const horizontalBarOptions = shallowRef({});
const pieOptions2 = shallowRef({});
const multipleLineOptions1 = shallowRef({});
const multipleLineOptions2 = shallowRef({});
onMounted(() => {
horizontalBarOptions.value = getHorizontalBarChart1(
["地球探测仪器", "计算机及其配套设备", "天文仪器", "分析仪器", "核仪器", "物理性能测试仪器", "医学科研仪器"],
[10, 10, 21, 25, 79, 95, 109],
false
);
pieOptions2.value = getPieOption2([
{ name: "美国", value: 27 },
{ name: "日本", value: 22 },
{ name: "德国", value: 18 },
{ name: "英国", value: 15 },
{ name: "韩国", value: 12 },
{ name: "荷兰", value: 8 },
{ name: "其他", value: 7 }
]);
// 获取仪器对美依赖度升高风险分析数据
const fetchDependencyRiskData = async () => {
try {
const data = await getScientificInstrumentDependencyRisk();
if (data && data.instrumentCountList && Array.isArray(data.instrumentCountList)) {
// 提取年份数据(去重并排序)
const allYears = [...new Set(data.instrumentCountList.flatMap(item => item.countList.map(c => c.year)))].sort();
// 转换数据格式以适应 getMultipleLineChart
const chartData = data.instrumentCountList.map(item => {
// 为每个仪器类型创建完整的年份数据序列
const values = allYears.map(year => {
const yearData = item.countList.find(c => c.year === year);
return yearData ? yearData.count : 0;
});
return {
name: item.name,
value: values
};
});
// 使用 getMultipleLineChart 生成图表配置
multipleLineOptions1.value = getMultipleLineChart({
dates: ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
data: [
{ name: "电子测量仪器", value: [45, 35, 25, 20, 20, 14, 15, 15, 23, 21] },
{ name: "分析仪器", value: [35, 33, 24, 21, 22, 18, 13, 19, 21, 31] },
{ name: "工艺试验仪器", value: [32, 22, 12, 11, 14, 15, 17, 13, 12, 26] },
{ name: "核仪器", value: [48, 38, 28, 28, 28, 18, 18, 18, 28, 28] }
]
dates: allYears.map(String), // 转换为字符串以匹配原数据格式
data: chartData
});
}
} catch (error) {
console.error("获取仪器对美依赖度升高风险分析数据失败:", error);
}
};
// 获取仪器国产化降低风险分析数据
const fetchLocalizationRiskData = async () => {
try {
const data = await getScientificInstrumentLocalizationRisk();
if (data && data.instrumentCountList && Array.isArray(data.instrumentCountList)) {
// 提取年份数据(去重并排序)
const allYears = [...new Set(data.instrumentCountList.flatMap(item => item.countList.map(c => c.year)))].sort();
// 转换数据格式以适应 getMultipleLineChart
const chartData = data.instrumentCountList.map(item => {
// 为每个仪器类型创建完整的年份数据序列
const values = allYears.map(year => {
const yearData = item.countList.find(c => c.year === year);
return yearData ? yearData.count : 0;
});
return {
name: item.name,
value: values
};
});
// 使用 getMultipleLineChart 生成图表配置
multipleLineOptions2.value = getMultipleLineChart({
dates: ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
data: [
{ name: "电子测量仪器", value: [45, 35, 25, 20, 20, 14, 15, 15, 23, 21] },
{ name: "分析仪器", value: [35, 33, 24, 21, 22, 18, 13, 19, 21, 31] },
{ name: "工艺试验仪器", value: [32, 22, 12, 11, 14, 15, 17, 13, 12, 26] },
{ name: "核仪器", value: [48, 38, 28, 28, 28, 18, 18, 18, 28, 28] }
]
dates: allYears.map(String), // 转换为字符串以匹配原数据格式
data: chartData
});
}
} catch (error) {
console.error("获取仪器国产化降低风险分析数据失败:", error);
}
};
// 获取各类别仪器对美依赖情况数据
const fetchDependencyCountData = async () => {
try {
const data = await getScientificInstrumentDependencyCount();
if (data && Array.isArray(data)) {
// 按照 count 降序排列
const sortedData = data.sort((a, b) => a.count - b.count);
// 提取仪器名称和对应的计数
const names = sortedData.map(item => item.name);
const counts = sortedData.map(item => item.count);
// 使用 getHorizontalBarChart1 生成图表配置
horizontalBarOptions.value = getHorizontalBarChart1(names, counts, false);
}
} catch (error) {
console.error("获取各类别仪器对美依赖情况数据失败:", error);
}
};
// 获取仪器进口国可替代性分析数据
const fetchOriginCountData = async () => {
try {
const data = await getScientificInstrumentOriginCount();
if (data && Array.isArray(data)) {
// 转换数据格式以适应 getPieOption2
// 数据结构应该是 [{ name: "国家名", value: 数量 }]
const pieData = data.map(item => ({
name: item.name,
value: (item.count * 100).toFixed(1)
}));
// 使用 getPieOption2 生成图表配置
pieOptions2.value = getPieOption2(pieData);
}
} catch (error) {
console.error("获取仪器进口国可替代性分析数据失败:", error);
}
};
onMounted(async () => {
// horizontalBarOptions.value = getHorizontalBarChart1(
// ["地球探测仪器", "计算机及其配套设备", "天文仪器", "分析仪器", "核仪器", "物理性能测试仪器", "医学科研仪器"],
// [10, 10, 21, 25, 79, 95, 109],
// false
// );
// pieOptions2.value = getPieOption2([
// { name: "美国", value: 27 },
// { name: "日本", value: 22 },
// { name: "德国", value: 18 },
// { name: "英国", value: 15 },
// { name: "韩国", value: 12 },
// { name: "荷兰", value: 8 },
// { name: "其他", value: 7 }
// ]);
// multipleLineOptions1.value = getMultipleLineChart({
// dates: ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
// data: [
// { name: "电子测量仪器", value: [45, 35, 25, 20, 20, 14, 15, 15, 23, 21] },
// { name: "分析仪器", value: [35, 33, 24, 21, 22, 18, 13, 19, 21, 31] },
// { name: "工艺试验仪器", value: [32, 22, 12, 11, 14, 15, 17, 13, 12, 26] },
// { name: "核仪器", value: [48, 38, 28, 28, 28, 18, 18, 18, 28, 28] }
// ]
// });
// multipleLineOptions2.value = getMultipleLineChart({
// dates: ["2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
// data: [
// { name: "电子测量仪器", value: [45, 35, 25, 20, 20, 14, 15, 15, 23, 21] },
// { name: "分析仪器", value: [35, 33, 24, 21, 22, 18, 13, 19, 21, 31] },
// { name: "工艺试验仪器", value: [32, 22, 12, 11, 14, 15, 17, 13, 12, 26] },
// { name: "核仪器", value: [48, 38, 28, 28, 28, 18, 18, 18, 28, 28] }
// ]
// });
// 获取各类别仪器对美依赖情况数据
await fetchDependencyCountData();
// 获取仪器进口国可替代性分析数据
await fetchOriginCountData();
// 获取仪器对美依赖度升高风险分析数据
await fetchDependencyRiskData();
// 获取仪器国产化降低风险分析数据
await fetchLocalizationRiskData();
});
</script>
......
......@@ -11,8 +11,8 @@
<div class="listWrap">
<div class="item" v-for="(item, index) in listData" :key="index" @click="handleEttClick(item)">
<div class="index" :class="{ isTopTen: index < 10 }">{{ index + 1 }}</div>
<div class="name">{{ item.name }}</div>
<div class="icon" :class="{ iconUp: item.isUp, iconDown: !item.isUp }"></div>
<div class="name">{{ item.name || item.nameEn }}</div>
<div class="icon" :class="{ iconUp: item.marketChange > 0, iconDown: item.marketChange < 0 }"></div>
</div>
</div>
</div>
......@@ -22,10 +22,13 @@
<Hint
text="法案核心意图在于通过税收优惠吸引制造业回流美国​,并在关键科技领域对中国进行遏制,限制中国获取先进技术、资本和市场渠道,从而延缓中国科技产业的发展速度。给半导体、新能源、人工智能等相关科技行业带来不小的短期压力。"
></Hint>
<div class="subPanel2-buttonlist" v-if="chainData.length > 0">
<ButtonList :list="chainData" :active-id="activeChainId" @click="setActiveChainId"></ButtonList>
</div>
<div class="chartsWrap">
<div class="right-main-content">
<div class="right-main-content-main">
<Fishbone :chainId="activeButtonId" />
<Fishbone :chainId="chainData.length > 0 ? activeChainId : activeButtonId" />
</div>
<div class="right-main-content-footer">
<div class="footer-item1">
......@@ -34,10 +37,13 @@
<img src="../../assets/images/warning.png" alt="" />
</div>
<div class="text">
{{ "中国企业45家(51.00%),受制裁3家(7.00%)" }}
{{
`国内企业数据量${cnEntityOnChainData.upstreamInternalCount}家(${cnEntityOnChainData.upstreamInternalRate}%),受制裁${cnEntityOnChainData.upstreamEntityCount}家(${cnEntityOnChainData.upstreamEntityRate}%)`
}}
<!-- {{ "中国企业45家(51.00%),受制裁3家(7.00%)" }} -->
</div>
</div>
<div class="footer-item1-top">{{ "基础支撑" }}</div>
<div class="footer-item1-top">{{ "上游" }}</div>
</div>
<div class="footer-item2">
<div class="footer-item2-bottom">
......@@ -45,10 +51,13 @@
<img src="../../assets/images/warning.png" alt="" />
</div>
<div class="text">
{{ "中国企业45家(51.00%),受制裁3家(7.00%)" }}
{{
`国内企业数据量${cnEntityOnChainData.midstreamInternalCount}家(${cnEntityOnChainData.midstreamInternalRate}%),受制裁${cnEntityOnChainData.midstreamEntityCount}家(${cnEntityOnChainData.midstreamEntityRate}%)`
}}
<!-- {{ "中国企业45家(51.00%),受制裁3家(7.00%)" }} -->
</div>
</div>
<div class="footer-item2-top">{{ "软件算法" }}</div>
<div class="footer-item2-top">{{ "中游" }}</div>
</div>
<div class="footer-item3">
<div class="footer-item3-bottom">
......@@ -56,10 +65,13 @@
<img src="../../assets/images/warning.png" alt="" />
</div>
<div class="text">
{{ "中国企业45家(51.00%),受制裁3家(7.00%)" }}
{{
`国内企业数据量${cnEntityOnChainData.downstreamInternalCount}家(${cnEntityOnChainData.downstreamInternalRate}%),受制裁${cnEntityOnChainData.downstreamEntityCount}家(${cnEntityOnChainData.downstreamEntityRate}%)`
}}
<!-- {{ "中国企业45家(51.00%),受制裁3家(7.00%)" }} -->
</div>
</div>
<div class="footer-item3-top">{{ "行业应用" }}</div>
<div class="footer-item3-top">{{ "下游" }}</div>
</div>
</div>
</div>
......@@ -77,7 +89,7 @@ import Hint from "./hint.vue";
import ButtonList from "@/components/buttonList/buttonList.vue";
import Fishbone from "./fishbone.vue";
import { getHorizontalBarChart2 } from "../../utils/charts";
import { getDomainDistribution, getChainEntities } from "@/api/exportControl";
import { getDomainDistribution, getChainEntities, getChainInfoByDomainId, getCnEntityOnChain } from "@/api/exportControl";
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
......@@ -151,6 +163,78 @@ const handleEttClick = item => {
});
window.open(route.href, "_blank");
};
// 处理点击事件
const handleChainClick = async chainId => {};
// 获取产业链信息数据
const chainData = ref([]);
const activeChainId = ref(chainData.value[0]?.id);
const setActiveChainId = id => {
activeChainId.value = id;
};
const fetchChainInfo = async () => {
try {
const data = await getChainInfoByDomainId(activeButtonId.value);
console.log("getChainInfoByDomainId", data);
if (data && Array.isArray(data)) {
// 将获取到的数据赋值给 chainData
chainData.value = data.map(item => ({
...item,
text: item.name
}));
console.log("chainData.value", chainData.value);
setActiveChainId(chainData.value[0].id);
} else {
setActiveChainId(null);
chainData.value = [];
}
} catch (error) {
console.error("获取产业链信息数据失败:", error);
}
};
const cnEntityOnChainData = ref({
upstreamInternalCount: 0,
upstreamInternalRate: 0,
upstreamEntityCount: 0,
upstreamEntityRate: 0,
midstreamInternalCount: 0,
midstreamInternalRate: 0,
midstreamEntityCount: 0,
midstreamEntityRate: 0,
downstreamInternalCount: 0,
downstreamInternalRate: 0,
downstreamEntityCount: 0,
downstreamEntityRate: 0
});
const fetchCnEntityOnChain = async () => {
try {
console.log("getCnEntityOnChain 111111", chainData.value);
const data = await getCnEntityOnChain(chainData.value.length > 0 ? activeChainId.value : activeButtonId.value);
console.log("getCnEntityOnChain", data);
if (!!data && Object.keys(data).length > 0) {
// 将获取到的数据赋值给 cnEntityOnChainData
cnEntityOnChainData.value = {
upstreamInternalCount: data.upstreamInternalCount || 0,
upstreamInternalRate: Math.floor(data.upstreamInternalRate * 100) || 0,
upstreamEntityCount: data.upstreamEntityCount || 0,
upstreamEntityRate: Math.floor(data.upstreamEntityRate * 100) || 0,
midstreamInternalCount: data.midstreamInternalCount || 0,
midstreamInternalRate: Math.floor(data.midstreamInternalRate * 100) || 0,
midstreamEntityCount: data.midstreamEntityCount || 0,
midstreamEntityRate: Math.floor(data.midstreamEntityRate * 100) || 0,
downstreamInternalCount: data.downstreamInternalCount || 0,
downstreamInternalRate: Math.floor(data.downstreamInternalRate * 100) || 0,
downstreamEntityCount: data.downstreamEntityCount || 0,
downstreamEntityRate: Math.floor(data.downstreamEntityRate * 100) || 0
};
console.log("getCnEntityOnChain 222222", chainData.value);
}
} catch (error) {
console.error("获取产业链信息数据失败:", error);
}
};
// 获取领域分布数据并更新图表
const fetchDomainDistribution = async () => {
try {
......@@ -193,6 +277,7 @@ const fetchChainEntities = async () => {
listData.value = data.map(item => ({
...item,
name: item.orgNameZh,
nameEn: item.orgName,
isUp: item.isUp
}));
}
......@@ -203,16 +288,31 @@ const fetchChainEntities = async () => {
onMounted(async () => {
fetchDomainDistribution();
// horizontalBarOptions.value = getHorizontalBarChart2(
// ["贸易", "军工", "金融业", "跨境电商", "半导体", "新能源"],
// [10, 21, 25, 79, 95, 109],
// false
// );
fetchChainEntities();
// 获取产业链信息数据
fetchChainInfo();
// 获取产业链中国企业实体信息查询
fetchCnEntityOnChain();
});
watch(() => activeButtonId.value, fetchChainEntities);
watch(
() => activeButtonId.value,
async () => {
await fetchChainEntities();
// 获取产业链信息数据
await fetchChainInfo();
// 获取产业链中国企业实体信息查询
await fetchCnEntityOnChain();
}
);
watch(
() => activeChainId.value,
async () => {
await fetchCnEntityOnChain();
}
);
</script>
<style lang="scss" scoped>
......@@ -225,6 +325,9 @@ watch(() => activeButtonId.value, fetchChainEntities);
display: flex;
flex-direction: column;
padding: 17px 18px 12px 18px;
&-buttonlist {
padding: 10px;
}
.chartsWrap {
flex: 1;
.right-main-content {
......
......@@ -124,9 +124,6 @@ const fetchKeyEntityList = async (date = "2025-11-11", keyword = "") => {
};
onMounted(async () => {
// 确保默认值正确设置
domainValue.value = domainOptions[0].value;
typeValue.value = typeOptions[0].value;
try {
const [entitiesGrowthTrendData, entitiesUpdateCountData] = await Promise.all([
getEntitiesGrowthTrend(),
......@@ -167,7 +164,7 @@ onMounted(async () => {
});
const domainOptions = [
{
value: "",
value: "all",
label: "全部"
},
{
......@@ -257,7 +254,7 @@ const domainOptions = [
];
const typeOptions = [
{
value: "",
value: "all",
label: "全部"
},
{
......@@ -273,14 +270,14 @@ const typeOptions = [
label: "地址"
}
];
const domainValue = ref("");
const typeValue = ref("");
const domainValue = ref("all");
const typeValue = ref("all");
const bar1Option = shallowRef({});
const bar1DataIsEmpty = ref(false);
watch(
[domainValue, typeValue],
async ([domain, type]) => {
let EntitiesChangeCount = await getEntitiesChangeCount(domain, type);
let EntitiesChangeCount = await getEntitiesChangeCount(domain == "all" ? "" : domain, type == "all" ? "" : type);
EntitiesChangeCount = _.reverse(EntitiesChangeCount);
bar1DataIsEmpty.value = EntitiesChangeCount.length === 0;
bar1Option.value = getBarChart(
......@@ -292,16 +289,6 @@ watch(
},
{ immediate: true }
);
// const options = [
// {
// value: "1",
// label: "人工智能"
// },
// {
// value: "2",
// label: "航空航天"
// }
// ];
const subPanel4 = ref([
{
name: "中国科学技术大学",
......
......@@ -76,18 +76,6 @@ import { getEntityFinancing, getEntityMarketValue, getKeyListedEntityList, getSa
import { useRoute, useRouter } from "vue-router";
const route = useRoute();
const router = useRouter();
const options = [
{
value: "1",
label: "人工智能"
},
{
value: "2",
label: "航空航天"
}
];
const value1 = ref("");
const value2 = ref("");
const value3 = ref("");
const bar1Option = shallowRef({});
const bar2Option = shallowRef({});
......@@ -119,6 +107,7 @@ const subPanel4 = ref([
// 获取重点上市企业列表数据
const fetchKeyListedEntityList = async (keyword = "") => {
try {
console.log("获取重点上市企业列表数据", route.query.startTime);
const data = await getKeyListedEntityList(route.query.startTime, keyword);
if (data && Array.isArray(data)) {
// 根据 fishbone-mock.json 的数据结构处理数据
......@@ -197,12 +186,12 @@ const fetchEntityFinancing = async () => {
// 按日期排序
const sortedData = data
.sort((a, b) => {
return new Date(a.name) - new Date(b.name);
return new Date(a.year) - new Date(b.year);
})
.filter((item, idx) => idx % 3 === 0);
// 提取 x 轴数据(日期)
const xAxisData = sortedData.map(item => item.name);
const xAxisData = sortedData.map(item => item.year);
// 提取 y 轴数据(融资数量)
const seriesData = sortedData.map(item => item.count);
......
......@@ -19,7 +19,7 @@
</CardCustom>
</div>
<div class="row">
<CardCustom title="历次制裁涉及实体数" :style="{ width: '798px', height: '422px' }">
<CardCustom title="历次制裁涉及实体类型数" :style="{ width: '798px', height: '422px' }">
<div class="subPanel3">
<div class="chartsWrap" :style="{ paddingBottom: '10px' }">
<Echarts :option="bar2Option" height="100%"></Echarts>
......@@ -46,7 +46,7 @@ import { Search } from "@element-plus/icons-vue";
import Echarts from "@/components/Chart/index.vue";
import { getBarChart, getLineChart, getPieOption1 } from "../../utils/charts";
import Hint from "./hint.vue";
import { getCountSanTypeByTime, getCountTypeByYear, getCountThisType } from "@/api/exportControl";
import { getCountSanTypeByTime, getCountTypeByYear, getCountThisType, getEnterpriseSanCount } from "@/api/exportControl";
import _ from "lodash";
import { useRoute } from "vue-router";
const route = useRoute();
......@@ -60,7 +60,7 @@ onMounted(async () => {
getCountSanTypeByTime(route.query.startTime),
getCountThisType("1"),
getCountTypeByYear(),
getCountThisType("2")
getEnterpriseSanCount()
]);
pie1Option.value = getPieOption1(
......
......@@ -13,7 +13,7 @@
import Echarts from "@/components/Chart/index.vue";
import { getPieOption } from "../../utils/charts";
import { ref, onMounted, shallowRef } from "vue";
import { getCountByDomain, getCountByType } from "@/api/exportControl";
import { getCountByDomain, getCountByType, getDomainDistribution } from "@/api/exportControl";
import _ from "lodash";
import { useRoute } from "vue-router";
const route = useRoute();
......@@ -22,7 +22,7 @@ const pie2Option = shallowRef({});
onMounted(async () => {
try {
const [countByDomainData, countByTypeData] = await Promise.all([
getCountByDomain(route.query.startTime),
getDomainDistribution(route.query.startTime),
getCountByType(route.query.startTime)
]);
pie1Option.value = getPieOption(
......@@ -30,7 +30,7 @@ onMounted(async () => {
.filter(item => item.count > 0)
.map(item => {
return {
name: item?.domain,
name: item?.name,
value: item?.count
};
})
......
<template>
<div class="message-bubble">
<div class="avatar-container" @click="handleClick">
<img :src="avatar" :alt="name" class="avatar" />
<img :src="avatar || avatarUser" :alt="name" class="avatar" />
</div>
<div class="bubble-container">
<div class="bubble">
......@@ -19,6 +19,8 @@
</template>
<script setup>
import avatarUser from "@/assets/images/avatar_user.png";
const emit = defineEmits(["click", "info-click"]);
defineProps({
avatar: {
......
......@@ -2,7 +2,7 @@
<div class="news-list">
<div v-for="(item, index) in listData" :key="index" class="news-item" @click="handleItemClick(item)">
<div class="news-image">
<img :src="item.image || newsImg" :alt="item.title" />
<img :src="item.avatar || newsImg" :alt="item.title" />
</div>
<div class="news-content">
<div class="news-header">
......
......@@ -91,7 +91,24 @@
<template #default>
<div class="box1">
<el-carousel ref="carouselRef" trigger="click" height="350px" :autoplay="true">
<div class="box1-left-arrow" @click="handleSwithCurPolicy('left')">
<div class="icon">
<img src="./assets/images/box1-left.png" alt="" />
</div>
</div>
<div class="box1-right-arrow" @click="handleSwithCurPolicy('right')">
<div class="icon">
<img src="./assets/images/box1-right.png" alt="" />
</div>
</div>
<el-carousel
ref="carouselRef"
height="350px"
:autoplay="true"
:interval="3000"
arrow="never"
indicator-position="none"
>
<el-carousel-item v-for="(item, index) in entitiesDataInfoList" :key="item.id + index">
<div>
<div class="box1-top">
......@@ -220,7 +237,7 @@
<template #default>
<div class="news-list">
<NewsList :list-data="newsList" @click="handleNewsInfoClick" />
<NewsList :list-data="newsList" @item-click="item => handleNewsInfoClick(item)" />
</div>
</template>
</custom-container>
......@@ -321,7 +338,7 @@
</div>
<div class="box3-content">
<div class="box3-content-title">商业管制清单(CCL)更新频度</div>
<el-table :data="tableData1" stripe style="width: 100%">
<el-table :data="tableData2" stripe style="width: 100%">
<el-table-column prop="year" label="年份" width="150" />
<el-table-column label="发布次数" width="200">
<template #default="scope">
......@@ -694,6 +711,7 @@ import _ from "lodash";
const handleCompClick = item => {
console.log("item", item);
if (item.entityType != 2) return;
const route = router.resolve({
path: "/companyPages",
query: {
......@@ -712,6 +730,8 @@ const trendOption = ref({});
const trendChecked = ref(false);
// 发布频度
const tableData1 = ref([]);
// CCL发布频度
const tableData2 = ref([]);
// 历次制裁过程
const sanctionProcessList = ref([]);
const sanctionPage = ref(1);
......@@ -727,10 +747,11 @@ const newsList = ref([]);
onMounted(async () => {
try {
const [dataCount, entitiesDataInfo, industryCountByYear, countDomainByYear] = await Promise.all([
const [dataCount, entitiesDataInfo, industryCountByYear, cclList, countDomainByYear] = await Promise.all([
getEntitiesDataCount(),
getEntitiesDataInfo(),
getIndustryCountByYear(1),
getIndustryCountByYear(13),
getCountDomainByYear(trendChecked.value)
]);
// 交换第二个和第三个元素
......@@ -742,6 +763,7 @@ onMounted(async () => {
});
entitiesDataInfoList.value = entitiesDataInfo || [];
const list = _.chain(industryCountByYear).filter("year").orderBy("year", "desc").value();
const cclList1 = _.chain(cclList).filter("year").orderBy("year", "desc").value();
const total = _.sumBy(list, "count");
tableData1.value = _.map(list, item => {
return {
......@@ -751,6 +773,14 @@ onMounted(async () => {
tags: item.domain
};
}).slice(0, 5);
tableData2.value = _.map(cclList1, item => {
return {
year: item.year,
num: item.count,
percent: item.count / total,
tags: item.domain
};
}).slice(0, 5);
console.log("countDomainByYear", countDomainByYear);
// 整理柱状图数据并应用到趋势图
if (countDomainByYear && countDomainByYear[0].yearDomainCount) {
......@@ -1194,6 +1224,7 @@ const fetchNewsInfo = async () => {
const data = await getNewsInfo();
if (data && Array.isArray(data)) {
newsList.value = data.map(item => ({
...item,
avatar: item.newsImage,
name: item.newsTitle,
time: formatTime(item.newsDate),
......@@ -1439,12 +1470,21 @@ const handleNewsInfoClick = item => {
const route = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
newsId: item.newsId
}
});
window.open(route.href, "_blank");
};
// 切换当前出口管制政策
const handleSwithCurPolicy = name => {
if (name === "left") {
carouselRef.value.prev();
} else {
carouselRef.value.next();
}
};
onMounted(async () => {
handleGetHylyList();
let chart1 = getMultiLineChart(chart1Data.value.title, chart1Data.value.data[0].value, chart1Data.value.data[1].value);
......@@ -1507,6 +1547,48 @@ const handleMediaClick = item => {
flex-direction: column;
gap: 20px;
position: relative;
.box1-left-arrow {
position: absolute;
z-index: 9999;
left: -20px;
top: 135px;
width: 24px !important;
height: 48px;
background: #e7f1ff;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
.icon {
width: 11px;
height: 18px;
img {
width: 100%;
height: 100%;
}
}
}
.box1-right-arrow {
position: absolute;
z-index: 9999;
right: -20px;
top:135px;
width: 24px;
height: 48px;
background: #e7f1ff;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
.icon {
width: 11px;
height: 18px;
img {
width: 100%;
height: 100%;
}
}
}
.box1-absolute {
position: absolute;
width: 240px;
......@@ -1887,10 +1969,14 @@ const handleMediaClick = item => {
}
.home-wrapper {
width: 100%;
height: calc(100vh - 96px);
position: relative;
overflow-y: hidden;
.home-main {
// width: 1400px;
padding: 0 5%;
margin: 0 auto;
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
.home-main-header {
......@@ -2044,44 +2130,9 @@ const handleMediaClick = item => {
gap: 20px;
.box1 {
display: flex;
gap: 10px;
position: relative;
// .box1-left {
// position: absolute;
// left: 0;
// top: 200px;
// width: 24px;
// height: 48px;
// background: #e7f1ff;
// display: flex;
// justify-content: center;
// align-items: center;
// cursor: pointer;
// .icon {
// width: 11px;
// height: 18px;
// img {
// width: 100%;
// height: 100%;
// }
// }
// }
.box1-right {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
cursor: pointer;
.icon {
width: 11px;
height: 18px;
img {
width: 100%;
height: 100%;
}
}
}
.box1-header {
height: 53px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
......
......@@ -139,6 +139,7 @@ export function getPieOption2(data, title) {
}
},
legend: {
type: "scroll",
icon: "rect",
top: "center",
right: "40",
......@@ -825,6 +826,7 @@ export const getMultipleLineChart = obj => {
containLabel: true
},
legend: {
type: "scroll",
right: "5%",
icon: "circle",
itemWidth: 15,
......@@ -835,7 +837,7 @@ export const getMultipleLineChart = obj => {
},
itemGap: 17,
data: obj.data.map((item, index) => {
return { name: item.name, itemStyle: { color: color[index] } };
return { name: item.name, itemStyle: { color: color[index % 4] } };
})
},
xAxis: {
......
......@@ -1698,10 +1698,14 @@ onMounted(async () => {
}
.home-wrapper {
width: 100%;
height: calc(100vh - 96px);
position: relative;
overflow-y: hidden;
.home-main {
// width: 1400px;
padding: 0 5%;
margin: 0 auto;
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
.home-main-header {
......
......@@ -352,7 +352,6 @@
/>
</el-select>
</div>
</div>
</div>
<div class="center-footer-layout">
......@@ -405,6 +404,7 @@
</div>
</div>
<div class="home-main-footer-main">
<div class="footer-main-item" v-for="item in universityList" :key="item.name" @click="handleClickToDetail">
<img :src="item.pic" style="height: 32px; width: 32px;" />
<div class="item-text">{{ item.name }}</div>
......@@ -894,7 +894,6 @@ onMounted(async () => {
let chart1 = getPieChart(chart1Data.value, colorList);
setChart(chart1, "chart1");
});
</script>
......
......@@ -1070,10 +1070,14 @@ onMounted(async () => {
box-shadow: none;
}
.home-wrapper {
width: 100%;
height: calc(100vh - 96px);
position: relative;
overflow-y: hidden;
.home-main {
// width: 1400px;
width: 100%;
margin: 0 auto;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
.home-main-header {
......@@ -1217,7 +1221,7 @@ onMounted(async () => {
right: 19px;
width: 6px;
height: 12px;
img{
img {
width: 100%;
height: 100%;
}
......
......@@ -100,10 +100,13 @@
</div>
<div class="box2-main">
<div class="box2-main-item" v-for="(item, index) in warningList" :key="index">
<div class="item-left" :class="{
<div
class="item-left"
:class="{
itemLeftStatus1: item.status === '一般风险',
itemLeftStatus2: item.status === '重大风险'
}">
}"
>
{{ item.status }}
</div>
<div class="item-right">
......@@ -131,14 +134,18 @@
<img src="./assets/images/TechnologyFigures-icon3.png" alt="" />
</div>
<!-- <div class="box3-header-title">{{ "人物动向" }}</div> -->
<div class="header-title"
style="width: 1560px; display: flex; justify-content: space-between; margin-top: 10px">
<div
class="header-title"
style="width: 1560px; display: flex; justify-content: space-between; margin-top: 10px"
>
<div class="box3-header-title">
{{ "人物动向" }}
</div>
<div style="display: flex; gap: 8px; margin-right: 12px">
<div v-for="value in peoDateList"
:class="peoDate !== value ? 'btn-box-samll' : 'btn-box-select-samll'">
<div
v-for="value in peoDateList"
:class="peoDate !== value ? 'btn-box-samll' : 'btn-box-select-samll'"
>
{{ value }}
</div>
</div>
......@@ -154,14 +161,18 @@
<div class="header-icon">
<img src="./assets/images/header-message.png" alt="" />
</div>
<div class="header-title"
style="width: 1595px; display: flex; justify-content: space-between; margin-top: 10px">
<div
class="header-title"
style="width: 1595px; display: flex; justify-content: space-between; margin-top: 10px"
>
<div>
{{ "重要人物言论及立场" }}
</div>
<div style="display: flex; gap: 8px; margin-right: 12px">
<div v-for="value in fields"
:class="fieldSelect !== value ? 'btn-box-samll' : 'btn-box-select-samll'">
<div
v-for="value in fields"
:class="fieldSelect !== value ? 'btn-box-samll' : 'btn-box-select-samll'"
>
{{ value }}
</div>
</div>
......@@ -178,18 +189,33 @@
<div class="box5-header">
<div class="box5-header-left">
<div class="box5-header-icon">
<img src="./assets/images/TechnologyFigures-icon1.png" alt=""
style="margin: 13px 21px 13px 21px; height: 22px" />
<img
src="./assets/images/TechnologyFigures-icon1.png"
alt=""
style="margin: 13px 21px 13px 21px; height: 22px"
/>
<div class="box5-header-title">{{ "科技人物观点词云" }}</div>
</div>
<div>
<div style="height: 45px; display: flex; align-items: center">
<el-select v-model="wordCloudvalue" style="width: 120px; height: 28px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="wordCloudfield" style="width: 120px; height: 28px; margin: 10px 24px 10px 5px">
<el-option v-for="item in fieldSelect" :key="item.value" :label="item.label"
:value="item.value" />
<el-select
v-model="wordCloudfield"
style="width: 120px; height: 28px; margin: 10px 24px 10px 5px"
>
<el-option
v-for="item in fieldSelect"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
......@@ -202,17 +228,22 @@
<div class="header-icon">
<img src="./assets/images/box3-header-icon.png" alt="" />
</div>
<div class="header-title"
style="display: flex; width: 740px; justify-content: space-between; align-items: center">
<div
class="header-title"
style="display: flex; width: 740px; justify-content: space-between; align-items: center"
>
<div>
{{ "科技人物观点涉及领域变化趋势" }}
</div>
<el-select v-model="areaSelect" style="width: 120px; height: 28px">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<div class="box6-main" id="box6Chart"></div>
......@@ -238,16 +269,22 @@
</div>
<div style="display: flex; width: 730px; justify-content: space-between; align-items: center">
<div class="box8-header-title">{{ "主要人物涉华观点统计" }}</div>
<div style="gap: 8px;display: flex;">
<div v-for="value in viewOption"
:class="viewSelect !== value ? 'btn-box-samll' : 'btn-box-select-samll'">
<div style="gap: 8px; display: flex">
<div
v-for="value in viewOption"
:class="viewSelect !== value ? 'btn-box-samll' : 'btn-box-select-samll'"
>
{{ value }}
</div>
<el-select v-model="wordCloudvalue" style="width: 120px; height: 28px; margin-top: -5px;">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
<el-select v-model="wordCloudvalue" style="width: 120px; height: 28px; margin-top: -5px">
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
</div>
</div>
......@@ -262,8 +299,13 @@
<DivideHeader id="position4" class="divide-header" :titleText="'资源库'"></DivideHeader>
<div class="home-main-footer-header">
<div class="btn-box">
<div class="btn" :class="{ btnActive: activeCate === cate }" v-for="(cate, index) in categoryList"
:key="index" @click="handleClickCate(cate)">
<div
class="btn"
:class="{ btnActive: activeCate === cate }"
v-for="(cate, index) in categoryList"
:key="index"
@click="handleClickCate(cate)"
>
{{ cate }}
</div>
</div>
......@@ -438,13 +480,22 @@ onMounted(() => {
}
.home-wrapper {
width: 100%;
height: calc(100vh - 96px);
position: relative;
overflow-y: hidden;
.home-main {
width: 1920px;
margin: 0 auto;
// width: 1920px;
// margin: 0 auto;
// background: url("./assets/images/background.png");
// background-repeat: no-repeat;
// background-color: #fff;
// background-size: contain;
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-repeat: no-repeat;
background-color: #fff;
background-size: contain;
background-size: 100% 100%;
.home-main-header {
display: flex;
......
......@@ -431,7 +431,8 @@ onMounted(async () => {
width: 1056px;
height: 1280px;
margin: 0 auto;
overflow: auto;
overflow: hidden;
overflow-y: auto;
.box1-item {
height: 128px;
......@@ -456,6 +457,7 @@ onMounted(async () => {
}
.center {
width: 850px;
margin-left: 18px;
.title {
......
......@@ -39,8 +39,13 @@
</div>
<div class="box2-main">
<div class="box2-main-tag-box">
<div class="tag" :class="{ tagActive: activeArea === item }" v-for="(item, index) in areaList" :key="index"
@click="handleClickArea(item.status)">
<div
class="tag"
:class="{ tagActive: activeArea === item }"
v-for="(item, index) in areaList"
:key="index"
@click="handleClickArea(item.status)"
>
{{ item.industryName }}
</div>
</div>
......@@ -94,13 +99,16 @@
</div>
</div>
<div class="box3-main-footer">
<div class="info">
{{ total }}项调查
</div>
<div class="info">{{ total }}项调查</div>
<div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" />
<el-pagination
:page-size="12"
background
layout="prev, pager, next"
:total="total"
@current-change="handleCurrentChange"
:current-page="currentPage"
/>
</div>
</div>
</div>
......@@ -131,7 +139,6 @@ import {
getThinkTankReportContent,
getThinkTankReportIndustry,
getThinkTankReportIndustryCloud
} from "@/api/thinkTank/overview";
import { useRouter } from "vue-router";
const router = useRouter();
......@@ -141,27 +148,25 @@ const box1Data =
ref(`包括经济竞争在内的美中竞争自2017年以来一直在定义美国外交政策。这两个经济体是世界上第一和第二大国家经济体,并且深深交织在一起。改变关系,无论多么必要,可能是昂贵的。因此,美国面临着一项挑战,确保其经济在耦合的战略竞争条件下满足国家的需求。
为了应对这一挑战,兰德大学的研究人员对美中竞争进行了经济和制度分析,进行了参与式的远见练习,以了解确保美国经济健康的长期路径,并创建了两个经济竞争游戏,探索多个国家在相互交流的同时确保经济健康的动态...`);
//获取内容摘要
const handleGetThinkTankReportAbstract = async () => {
try {
const res = await getThinkTankReportAbstract(router.currentRoute._value.params.id);
console.log("内容摘要", res);
if (res.code === 200 && res.data) {
box1Data.value = res.data
box1Data.value = res.data;
}
} catch (error) {
console.error("获取内容摘要error", error);
}
};
// 涉及科技领域
const areaList = ref([]);
const activeArea = ref(6);
const handleClickArea = area => {
activeArea.value = area;
handleGetThinkTankReportIndustryCloud()
handleGetThinkTankReportIndustryCloud();
};
const box2Data = ref([
// {
......@@ -204,21 +209,20 @@ const handleGetThinkTankReportIndustryCloud = async () => {
const params = {
id: router.currentRoute._value.params.id,
industryId: activeArea.value
}
};
const res = await getThinkTankReportIndustryCloud(params);
console.log("科技领域词云", res);
if (res.code === 200 && res.data) {
const data = []
const data = [];
res.data.map(item => {
data.push(
{
data.push({
name: item.clause,
value: item.count
})
box2Data.value = data
});
box2Data.value = data;
const box2Chart = getWordCloudChart(box2Data.value);
setChart(box2Chart, "box2Chart");
})
});
}
} catch (error) {
console.error("获取科技领域词云error", error);
......@@ -230,7 +234,7 @@ const handleGetThinkTankReportIndustry = async () => {
const res = await getThinkTankReportIndustry(router.currentRoute._value.params.id);
console.log("涉及科技领域", res);
if (res.code === 200 && res.data) {
areaList.value = res.data
areaList.value = res.data;
}
} catch (error) {
console.error("获取涉及科技领域error", error);
......@@ -378,10 +382,10 @@ const majorOpinions = ref([
}
]);
// 处理页码改变事件
const currentPage = ref(1)
const currentPage = ref(1);
const handleCurrentChange = page => {
currentPage.value = page;
handleGetThinkDynamicsReport()
handleGetThinkDynamicsReport();
};
//获取报告主要观点
const handleGetThinkTankReportContent = async () => {
......@@ -389,19 +393,18 @@ const handleGetThinkTankReportContent = async () => {
const res = await getThinkTankReportContent(router.currentRoute._value.params.id);
console.log("主要观点", res);
if (res.code === 200 && res.data) {
majorOpinions.value = res.data.content
majorOpinions.value = res.data.content;
}
} catch (error) {
console.error("获取主要观点error", error);
}
};
onMounted(() => {
handleGetThinkTankReportAbstract()
handleGetThinkTankReportContent()
handleGetThinkTankReportIndustry()
handleGetThinkTankReportIndustryCloud()
handleGetThinkTankReportAbstract();
handleGetThinkTankReportContent();
handleGetThinkTankReportIndustry();
handleGetThinkTankReportIndustryCloud();
});
</script>
......@@ -506,14 +509,15 @@ onMounted(() => {
line-height: 30px;
letter-spacing: 0px;
text-align: justify;
display: -webkit-box;
/* 使用Webkit的弹性盒模型 */
-webkit-box-orient: vertical;
/* 垂直排列 */
-webkit-line-clamp: 9;
/* 限制显示9行 */
overflow: hidden;
/* 隐藏超出部分 */
overflow-y: auto;
// display: -webkit-box;
// /* 使用Webkit的弹性盒模型 */
// -webkit-box-orient: vertical;
// /* 垂直排列 */
// -webkit-line-clamp: 9;
// /* 限制显示9行 */
// overflow: hidden;
// /* 隐藏超出部分 */
}
.box1-footer {
......@@ -667,6 +671,9 @@ onMounted(() => {
line-height: 26px;
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.desc {
......@@ -678,6 +685,9 @@ onMounted(() => {
line-height: 22px;
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
......
......@@ -14,7 +14,7 @@
{{ thinkTank.describe }}
</div>
<div class="center-footer">
<div class="tag" v-for="tag in thinkTank.tags">{{ tag.industryName }}</div>
<div class="tag" v-for="tag,index in thinkTank.tags" :key="index">{{ tag.industryName }}</div>
</div>
</div>
......@@ -114,7 +114,10 @@ onMounted(async () => {
.header-top-left {
width: 88px;
height: 88px;
background: purple;
img{
width: 100%;
height: 100%;
}
}
.header-top-center {
......
......@@ -14,7 +14,7 @@
<el-option @click="handleGetThinkDynamicsReport()" v-for="item in yearList" :key="item.value"
:label="item.label" :value="item.value" />
</el-select>
<el-select v-model="sort" placeholder="发布时间" style="width: 120px">
<el-select v-model="sort" placeholder="发布时间" style="width: 120px; margin-left: 8px;">
<el-option @click="handleGetThinkDynamicsReport()" :key="true" label="正序" :value="true" />
<el-option @click="handleGetThinkDynamicsReport()" :key="false" label="倒序" :value="false" />
</el-select>
......@@ -503,6 +503,9 @@ onMounted(async () => {
font-size: 18px;
font-weight: 700;
line-height: 24px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.footer-card-footer {
......
......@@ -335,12 +335,10 @@
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
全部领域
</el-checkbox>
<el-checkbox-group v-model="selectedAreaList">
<el-checkbox v-for="(research, index) in areaList" :key="index" :label="research.id"
@change="handleCheckedAreaChange()" class="filter-checkbox">
<el-checkbox v-for="research in areaList" :key="research.id" v-model="selectedAreaList"
:label="research.id" @change="handleCheckedAreaChange()" class="filter-checkbox">
{{ research.name }}
</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
......@@ -1302,9 +1300,15 @@ onMounted(async () => {
}
.home-wrapper {
width: 100%;
height: calc(100vh - 96px);
position: relative;
overflow-y: hidden;
.home-main {
width: 1920px;
margin: 0 auto;
width: 100%;
height: 100%;
overflow-y: auto;
background: url("./assets/images/background.png");
background-size: 100% 100%;
......@@ -1528,6 +1532,9 @@ onMounted(async () => {
font-weight: 400;
line-height: 32px;
letter-spacing: 0px;
overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
}
.rank1 {
......
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论