提交 74552a5c authored 作者: Vicky's avatar Vicky

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

...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
"json5": "^2.2.3", "json5": "^2.2.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"pdfjs-dist": "^5.4.449",
"vue": "^3.4.0", "vue": "^3.4.0",
"vue-router": "^4.2.5" "vue-router": "^4.2.5"
}, },
...@@ -664,6 +665,244 @@ ...@@ -664,6 +665,244 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/@napi-rs/canvas": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas/-/canvas-0.1.86.tgz",
"integrity": "sha512-hOkywnrkdFdVpsuaNsZWfEY7kc96eROV2DuMTTvGF15AZfwobzdG2w0eDlU5UBx3Lg/XlWUnqVT5zLUWyo5h6A==",
"optional": true,
"workspaces": [
"e2e/*"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"optionalDependencies": {
"@napi-rs/canvas-android-arm64": "0.1.86",
"@napi-rs/canvas-darwin-arm64": "0.1.86",
"@napi-rs/canvas-darwin-x64": "0.1.86",
"@napi-rs/canvas-linux-arm-gnueabihf": "0.1.86",
"@napi-rs/canvas-linux-arm64-gnu": "0.1.86",
"@napi-rs/canvas-linux-arm64-musl": "0.1.86",
"@napi-rs/canvas-linux-riscv64-gnu": "0.1.86",
"@napi-rs/canvas-linux-x64-gnu": "0.1.86",
"@napi-rs/canvas-linux-x64-musl": "0.1.86",
"@napi-rs/canvas-win32-arm64-msvc": "0.1.86",
"@napi-rs/canvas-win32-x64-msvc": "0.1.86"
}
},
"node_modules/@napi-rs/canvas-android-arm64": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.86.tgz",
"integrity": "sha512-IjkZFKUr6GzMzzrawJaN3v+yY3Fvpa71e0DcbePfxWelFKnESIir+XUcdAbim29JOd0JE0/hQJdfUCb5t/Fjrw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-darwin-arm64": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.86.tgz",
"integrity": "sha512-PUCxDq0wSSJbtaOqoKj3+t5tyDbtxWumziOTykdn3T839hu6koMaBFpGk9lXpsGaPNgyFpPqjxhtsPljBGnDHg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-darwin-x64": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.86.tgz",
"integrity": "sha512-rlCFLv4Rrg45qFZq7mysrKnsUbMhwdNg3YPuVfo9u4RkOqm7ooAJvdyDFxiqfSsJJTqupYqa9VQCUt8WKxKhNQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-linux-arm-gnueabihf": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.86.tgz",
"integrity": "sha512-6xWwyMc9BlDBt+9XHN/GzUo3MozHta/2fxQHMb80x0K2zpZuAdDKUYHmYzx9dFWDY3SbPYnx6iRlQl6wxnwS1w==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-linux-arm64-gnu": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.86.tgz",
"integrity": "sha512-r2OX3w50xHxrToTovOSQWwkVfSq752CUzH9dzlVXyr8UDKFV8dMjfa9hePXvAJhN3NBp4TkHcGx15QCdaCIwnA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-linux-arm64-musl": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.86.tgz",
"integrity": "sha512-jbXuh8zVFUPw6a9SGpgc6EC+fRbGGyP1NFfeQiVqGLs6bN93ROtPLPL6MH9Bp6yt0CXUFallk2vgKdWDbmW+bw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-linux-riscv64-gnu": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.86.tgz",
"integrity": "sha512-9IwHR2qbq2HceM9fgwyL7x37Jy3ptt1uxvikQEuWR0FisIx9QEdt7F3huljCky76aoouF2vSd0R2fHo3ESRoPw==",
"cpu": [
"riscv64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-linux-x64-gnu": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.86.tgz",
"integrity": "sha512-Jor+rhRN6ubix+D2QkNn9XlPPVAYl+2qFrkZ4oZN9UgtqIUZ+n+HljxhlkkDFRaX1mlxXOXPQjxaZg17zDSFcQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-linux-x64-musl": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.86.tgz",
"integrity": "sha512-A28VTy91DbclopSGZ2tIon3p8hcVI1JhnNpDpJ5N9rYlUnVz1WQo4waEMh+FICTZF07O3coxBNZc4Vu4doFw7A==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-win32-arm64-msvc": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.86.tgz",
"integrity": "sha512-q6G1YXUt3gBCAS2bcDMCaBL4y20di8eVVBi1XhjUqZSVyZZxxwIuRQHy31NlPJUCMiyNiMuc6zeI0uqgkWwAmA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@napi-rs/canvas-win32-x64-msvc": {
"version": "0.1.86",
"resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.86.tgz",
"integrity": "sha512-X0g46uRVgnvCM1cOjRXAOSFSG63ktUFIf/TIfbKCUc7QpmYUcHmSP9iR6DGOYfk+SggLsXoJCIhPTotYeZEAmg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
...@@ -5164,6 +5403,17 @@ ...@@ -5164,6 +5403,17 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/pdfjs-dist": {
"version": "5.4.449",
"resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-5.4.449.tgz",
"integrity": "sha512-CegnUaT0QwAyQMS+7o2POr4wWUNNe8VaKKlcuoRHeYo98cVnqPpwOXNSx6Trl6szH02JrRcsPgletV6GmF3LtQ==",
"engines": {
"node": ">=20.16.0 || >=22.3.0"
},
"optionalDependencies": {
"@napi-rs/canvas": "^0.1.81"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
"json5": "^2.2.3", "json5": "^2.2.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
"pdfjs-dist": "^5.4.449",
"vue": "^3.4.0", "vue": "^3.4.0",
"vue-router": "^4.2.5" "vue-router": "^4.2.5"
}, },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -9,58 +9,8 @@ ...@@ -9,58 +9,8 @@
</div> </div>
<div class="brand-text" @click="handleToHome"> <div class="brand-text" @click="handleToHome">
<div class="text-ch">某方向风险监测预警系统</div> <div class="text-ch">某方向风险监测预警系统</div>
<!-- <div class="text-en">
National Science and Technology Security Risk Monitoring and Early Warning System
</div> -->
</div> </div>
</div> </div>
<!-- <div class="nav-menu">
<el-dropdown @command="handleHomeCommand" class="home-dropdown">
<div class="nav-link dropdown-trigger">
<el-icon>
<House />
</el-icon>
<span>首页</span>
<el-icon class="dropdown-arrow">
<ArrowDown />
</el-icon>
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="/billHome">法案首页</el-dropdown-item>
<el-dropdown-item command="/decree">政令首页</el-dropdown-item>
<el-dropdown-item command="/thinkTank">智库首页</el-dropdown-item>
<el-dropdown-item command="/exportControl">出口管制</el-dropdown-item>
<el-dropdown-item command="/finance">投融资限制</el-dropdown-item>
<el-dropdown-item command="/marketAccessRestrictions">市场准入限制</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<div class="nav-link">
<el-icon>
<User />
</el-icon>
<span>国家</span>
</div>
<div class="nav-link">
<el-icon>
<Location />
</el-icon>
<span>领域</span>
</div>
<div class="nav-link">
<el-icon>
<Document />
</el-icon>
<span>要素</span>
</div>
<div class="nav-link">
<el-icon>
<Bell />
</el-icon>
<span>事件</span>
</div>
</div> -->
<div class="user-info"> <div class="user-info">
<div class="email"> <div class="email">
<img src="@/assets/icons/header-icon.png" alt="" /> <img src="@/assets/icons/header-icon.png" alt="" />
...@@ -73,18 +23,16 @@ ...@@ -73,18 +23,16 @@
</nav> </nav>
</el-header> </el-header>
<!-- 面包屑导航 -->
<!-- <Breadcrumb /> -->
<el-main class="main-container"> <el-main class="main-container">
<router-view /> <router-view />
</el-main> </el-main>
<div class="ai-btn" @click="openAiBox"> <div class="ai-btn" @click="openAiBox">
<div class="icon"> <div class="icon">
<img src="@/assets/icons/ai-icon.png" alt="" /> <img src="@/assets/icons/ai-icon.png" alt="" />
</div>
<div class="text">智能问答</div>
</div> </div>
<div class="text">智能问答</div>
</div>
<div class="ai-dialog" v-if="isShowAiBox"> <div class="ai-dialog" v-if="isShowAiBox">
<AiBox @close="closeAiBox" /> <AiBox @close="closeAiBox" />
</div> </div>
...@@ -93,14 +41,31 @@ ...@@ -93,14 +41,31 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, computed, onMounted } from "vue";
import { Monitor, House, User, Location, Document, Bell, Message, ArrowDown } from "@element-plus/icons-vue"; import { Monitor, House, User, Location, Document, Bell, Message, ArrowDown } from "@element-plus/icons-vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import Breadcrumb from "@/components/BreadCrumb/index.vue"; import Breadcrumb from "@/components/BreadCrumb/index.vue";
import AiBox from "./components/AiBox.vue"; import AiBox from "./components/AiBox.vue";
import {getPersonType} from '@/api/common/index'
// import { useDraggable } from "@vueuse/core";
const router = useRouter(); const router = useRouter();
// const target = ref(null);
// const { x, y, isDragging } = useDraggable(target, {
// initialValue: { x: 1770, y: 800 },
// onStart: () => console.log("开始拖动"),
// onEnd: () => console.log("结束拖动")
// });
// const style = computed(() => ({
// position: "absolute",
// left: `${x.value}px`,
// top: `${y.value}px`,
// cursor: isDragging.value ? "grabbing" : "grab"
// }));
const handleToHome = () => { const handleToHome = () => {
router.push({ router.push({
path: "/overview" path: "/overview"
...@@ -120,6 +85,30 @@ const openAiBox = () => { ...@@ -120,6 +85,30 @@ const openAiBox = () => {
const handleHomeCommand = command => { const handleHomeCommand = command => {
router.push(command); router.push(command);
}; };
const personTypeList = ref([])
// 获取人物类别
const handleGetPersonType = async() => {
try {
const res = await getPersonType()
console.log('res', res);
if(res.code === 200) {
personTypeList.value = res.data
} else {
personTypeList.value = []
}
window.sessionStorage.setItem('personTypeList', JSON.stringify(personTypeList.value))
} catch (error) {
}
}
onMounted(() => {
handleGetPersonType()
})
</script> </script>
<style> <style>
...@@ -141,6 +130,7 @@ body { ...@@ -141,6 +130,7 @@ body {
} }
.el-popover { .el-popover {
width: 100%;
font-family: "Microsoft YaHei"; font-family: "Microsoft YaHei";
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-style: Regular; font-style: Regular;
...@@ -150,6 +140,10 @@ body { ...@@ -150,6 +140,10 @@ body {
letter-spacing: 0px; letter-spacing: 0px;
text-align: justify; text-align: justify;
} }
.el-popper[data-popper-placement^=top]>.el-popper__arrow:before {
display: none;
}
</style> </style>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -315,11 +309,17 @@ body { ...@@ -315,11 +309,17 @@ body {
.wrapper { .wrapper {
position: relative; position: relative;
.target {
// position: absolute;
// bottom: 20%;
// right: 46px;
z-index: 9999;
}
.ai-btn { .ai-btn {
position: absolute; position: absolute;
bottom: 20%; bottom: 240px;
right: 46px; right: 10px;
z-index: 9999; z-index: 9999;
cursor: pointer; cursor: pointer;
......
import request from "@/api/request.js";
// 风险信号
export function getRiskSignal(params) {
return request({
method: 'GET',
url: `/api/commonFeature/riskSignal/${params.moduleId}`,
})
}
// 新闻资讯
export function getNews(params) {
return request({
method: 'GET',
url: `/api/commonFeature/news/${params.moduleId}`,
})
}
// 社交媒体
export function getRemarks(params) {
return request({
method: 'GET',
url: `/api/commonFeature/remarks/${params.moduleId}`,
})
}
// 获取人物全局信息 通过personId 获取personType
export function getPersonSummaryInfo(params) {
return request({
method: 'GET',
url: `/api/personHomepage/summaryInfo/${params.personId}`,
})
}
// 获取人物类别
export function getPersonType() {
return request({
method: 'GET',
url: `/api/commonDict/personType`,
})
}
\ No newline at end of file
...@@ -34,10 +34,11 @@ export function getDecreeYearOrder(params) { ...@@ -34,10 +34,11 @@ export function getDecreeYearOrder(params) {
} }
// 政令涉及领域 // 政令涉及领域
export function getDecreeArea() { export function getDecreeArea(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/administrativeOrderOverview/industry`, url: `/api/administrativeOrderOverview/industry/${params.year}`,
params
}) })
} }
......
...@@ -46,4 +46,15 @@ export function getDecreeSummary(params) { ...@@ -46,4 +46,15 @@ export function getDecreeSummary(params) {
url: `/api/administrativeOrderInfo/summary/${params.id}`, url: `/api/administrativeOrderInfo/summary/${params.id}`,
params params
}) })
}
// 获取报告原文
/**
* @param {id}
*/
export function getDecreeReport(params) {
return request({
method: 'GET',
url: `/api/administrativeOrderInfo/contentUrl/${params.id}`,
})
} }
\ No newline at end of file
import http from './request'
/**
* 智库信息相关的API接口
* 假设您有一个名为 'http' 的对象来处理请求,且已在 http 封装中处理了 token。
* 例如:
* import http from '@/utils/request';
*/
// --- 智库信息接口 ---
/**
* @description 根据智库ID获取智库基本信息
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段类型为 ThinkTankBasicInfoVO
* @returns {string} data.country - 国家
* @returns {string} data.foundingDate - 成立时间
* @returns {string} data.position - 位置
* @returns {string} data.nature - 机构性质
* @returns {number} data.memnum - 成员数
* @returns {number} data.budget - 年度预算
*/
export const getThinkTankBasicInfo = (params) => {
// 假设 http 封装中会自动处理 token
return http.get(`/thinkTankInfo/basic/${params.id}`);
}
/**
* @description 根据智库ID获取分支机构信息
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankBranchVO>
* @returns {Array<object>} data[] - 分支机构列表
* @returns {string} data[].city - 城市
* @returns {string} data[].area - 区域
* @returns {boolean} data[].hq - 是否总部
*/
export const getThinkTankBranchInfo = (params) => {
return http.get(`/thinkTankInfo/branch/${params.id}`);
}
/**
* @description 根据智库ID获取经费来源
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankFundsSourceVO>
* @returns {Array<object>} data[] - 经费来源列表
* @returns {number} data[].amount - 金额
* @returns {string} data[].institution - 机构
* @returns {number} data[].percent - 占比
*/
export const getThinkTankFundsSource = (params) => {
return http.get(`/thinkTankInfo/fundsSource/${params.id}`);
}
/**
* @description 根据智库ID获取经费统计
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段类型为 ThinkTankFundsTotalVO
* @returns {number} data.totalJe - 总金额
* @returns {number} data.zfJe - 政府资金
* @returns {number} data.otherJe - 非政府资金
*/
export const getThinkTankFundsTotal = (params) => {
return http.get(`/thinkTankInfo/fundsTotal/${params.id}`);
}
/**
* @description 根据智库ID获取成员列表
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankPersonVO>
* @returns {Array<object>} data[] - 成员列表
* @returns {string} data[].name - 姓名
* @returns {string} data[].describe - 描述
*/
export const getThinkTankPersonList = (params) => {
return http.get(`/thinkTankInfo/person/${params.id}`);
}
/**
* @description 根据智库ID获取政策情况
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @param {Array<string>} [params.researchTypeIds] - 研究类型ID列表 (Query参数)
* @returns {Promise<object>} 响应数据,data字段类型为 ThinkTankPolicyCountVO
* @returns {Array<object>} data.statusVoList[] - 状态列表
* @returns {string} data.statusVoList[].statusName - 状态名称
* @returns {number} data.statusVoList[].statusNum - 状态数量
* @returns {Array<object>} data.policyVoList[] - 政策列表
* @returns {string} data.policyVoList[].content - 政策内容
* @returns {string} data.policyVoList[].status - 政策状态
* @returns {number} data.policyVoList[].reportId - 报告id
* @returns {string} data.policyVoList[].name - 报告名称
* @returns {string} data.policyVoList[].times - 报告时间 (date格式)
*/
export const getThinkTankPolicyInfo = (params) => {
const { id, ...queryParams } = params;
// 假设 http.get 会将 queryParams 作为查询参数传递
return http.get(`/thinkTankInfo/policy/${id}`, { params: queryParams });
}
/**
* @description 获取智库报告类型列表
* @returns {Promise<object>} 响应数据,data字段为数组 List<DThinkTankReportType>
* @returns {Array<object>} data[] - 报告类型列表
* @returns {number} data[].id - 主键
* @returns {string} data[].typeId - 报告类型id
* @returns {string} data[].typeName - 报告类型
*/
export const getThinkTankReportTypeList = () => {
return http.get('/thinkTankInfo/reportType');
}
/**
* @description 根据智库ID获取研究领域情况
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankResearchAreaVO>
* @returns {Array<object>} data[] - 研究领域列表
* @returns {string} data[].describe - 研究领域描述
* @returns {string} data[].time - 研究时间范围
*/
export const getThinkTankResearchArea = (params) => {
return http.get(`/thinkTankInfo/researchArea/${params.id}`);
}
// /thinkTankInfo/report/{id}
export const getThinkTankReport = (params) => {
return http.get(`/thinkTankInfo/report/${params.id}`);
}
/**
* @description 根据智库ID获取智库全局信息
* @param {object} params - 请求参数
* @param {number|string} params.id - 智库id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段类型为 ThinkTankInfoVO
* @returns {string} data.name - 智库名称
* @returns {string} data.describe - 智库描述
* @returns {string} data.ename - 智库英文名
* @returns {string} data.url - 智库网址
* @returns {Array<string>} data.tags[] - 智库标签列表
*/
export const getThinkTankSummary = (params) => {
return http.get(`/thinkTankInfo/summary/${params.id}`);
}
// --- 智库报告接口 ---
/**
* @description 根据报告ID获取报告内容
* @param {object} params - 请求参数
* @param {number|string} params.id - 报告id (路径参数, 必须)
* @param {number} [params.currentPage] - 当前页码 (Query参数)
* @param {number} [params.pageSize] - 分页大小 (Query参数)
* @returns {Promise<object>} 响应数据,data字段类型为 Page<ThinkTankReportContentVO> (分页内容对象)
*/
export const getThinkTankReportContent = (params) => {
const { id, ...queryParams } = params;
return http.get(`/thinkTankReport/content/${id}`, { params: queryParams });
}
/**
* @description 根据报告ID获取政策情况
* @param {object} params - 请求参数
* @param {number|string} params.id - 报告id (路径参数, 必须)
* @param {Array<string>} [params.statusList] - 政策状态ID列表 (Query参数)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankReportPolicyVO>
* @returns {Array<object>} data[] - 政策列表
* @returns {string} data[].content - 政策内容
* @returns {string} data[].status - 政策状态
*/
export const getThinkTankReportPolicy = (params) => {
const { id, ...queryParams } = params;
return http.get(`/thinkTankReport/policy/${id}`, { params: queryParams });
}
/**
* @description 根据报告ID获取报告全局信息
* @param {object} params - 请求参数
* @param {number|string} params.id - 报告id (路径参数, 必须)
* @returns {Promise<object>} 响应数据,data字段类型为 ThinkTankReportDetailVO
* @returns {string} data.name - 报告名称
* @returns {string} data.times - 报告时间 (date格式)
* @returns {string} data.ename - 报告英文名称
* @returns {string} data.summary - 报告摘要
* @returns {string} data.thinkTankName - 智库名称
* @returns {Array<string>} data.tags[] - 报告标签列表
* @returns {Array<string>} data.researchTypes[] - 报告研究类型列表
*/
export const getThinkTankReportSummary = (params) => {
return http.get(`/thinkTankReport/summary/${params.id}`);
}
// --- 智库概览接口 ---
/**
* @description 获取概览智库政策
* @param {object} [params] - 请求参数
* @param {Array<string>} [params.researchTypeIds] - 研究类型ID列表 (Query参数)
* @param {Array<string>} [params.statusList] - 政策状态ID列表 (Query参数)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankPolicyVO>
* @returns {Array<object>} data[] - 政策列表
* @returns {string} data[].content - 政策内容
* @returns {string} data[].status - 政策状态
* @returns {number} data[].reportId - 报告id
* @returns {string} data[].name - 报告名称
* @returns {string} data[].times - 报告时间 (date格式)
*/
export const getOverviewPolicy = (params = {}) => {
// 假设 http.get 会将 params 作为查询参数传递
return http.get('/thinkTankOverview/policy', { params });
}
/**
* @description 获取概览智库报告
* @param {object} [params] - 请求参数
* @param {Array<string>} [params.areas] - 区域名称列表 (Query参数)
* @param {Array<string>} [params.researchTypeIds] - 研究类型ID列表 (Query参数)
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankSummaryReportVO>
* @returns {Array<object>} data[] - 报告列表
* @returns {number} data[].id - 报告id
* @returns {string} data[].name - 报告名称
* @returns {string} data[].times - 报告时间 (date格式)
* @returns {string} data[].thinkTankName - 智库名称
*/
export const getOverviewReport = (params = {}) => {
return http.get('/thinkTankOverview/report', { params });
}
/**
* @description 获取智库列表
* @returns {Promise<object>} 响应数据,data字段为数组 List<ThinkTankListVO>
* @returns {Array<object>} data[] - 智库列表
* @returns {number} data[].id - 智库id
* @returns {string} data[].name - 智库名称
* @returns {string} data[].describe - 智库描述
* @returns {string} data[].country - 智库国家
* @returns {Array<string>} data[].tags[] - 智库标签列表
*/
export const getThinkTankList = () => {
return http.get('/thinkTankOverview/thinkTanks');
}
// 获取智库报告研究类型 /thinkTankInfo/researchType
export const getThinkTankResearchType = () => {
return http.get('/thinkTankInfo/researchType');
}
...@@ -14,7 +14,7 @@ export function getGovOrgBasicInfo(params) { ...@@ -14,7 +14,7 @@ export function getGovOrgBasicInfo(params) {
// 最新动态 // 最新动态
/** /**
* @param { orgId, cRelated, currentPage, pageSize } * @param { orgId, cRelated,dynamicsType, currentPage, pageSize }
*/ */
export function getGovOrgLatestDynamics(params) { export function getGovOrgLatestDynamics(params) {
return request({ return request({
...@@ -61,4 +61,84 @@ export function getGovOrgOpinions(params) { ...@@ -61,4 +61,84 @@ export function getGovOrgOpinions(params) {
url: `/api/governmentOrg/keyWord/${params.orgId}`, url: `/api/governmentOrg/keyWord/${params.orgId}`,
params params
}) })
}
// 人物关系
/**
* @param { orgId }
*/
export function getPersonRelation(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/personRelation/${params.orgId}`,
params
})
}
// 对华制裁 ---------------------------------------
// 实体清单新增数量
/**
* @param { orgId }
*/
export function getGrowthNum(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/growthNum/${params.orgId}`,
params
})
}
// 实体清单新增数量变化趋势
/**
* @param { orgId }
*/
export function getGrowthTrend(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/growthTrend/${params.orgId}`,
params
})
}
// 实体清单新增企业领域分布
/**
* @param { orgId }
*/
export function getEntityListField(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/entityListField/${params.year}/${params.orgId}`,
params
})
}
// 232调查单新增数量
/**
* @param { orgId }
*/
export function getGrowth232Num(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/growth232Num/${params.orgId}`,
params
})
}
// 232调查新增数量变化趋势
/**
* @param { orgId }
*/
export function getGrowth232Trend(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/growth232Trend/${params.orgId}`,
params
})
}
// 232调查新增企业领域分布
/**
* @param { orgId }
*/
export function getSection232Field(params) {
return request({
method: 'GET',
url: `/api/governmentOrg/section232Field/${params.startDate}/${params.orgId}`,
params
})
} }
\ No newline at end of file
import request from "@/api/request.js";
// 概览页--------------------------------------------------------------------
// 概览统计
export function getStatCount() {
return request({
method: 'GET',
url: `/api/marketsearchHome/statCount`
})
}
// 分类接口
export function getStatSort() {
return request({
method: 'GET',
url: `/api/marketsearchHome/statSort`
})
}
// 调查进展
export function getStatDetails() {
return request({
method: 'GET',
url: `/api/marketsearchHome/statDetails`
})
}
// 调查数量
/**
* @param {byYorM}
*/
export function getStatNum(params) {
return request({
method: 'GET',
url: `/api/marketsearchHome/statNum`,
params
})
}
// 制裁领域分布
/**
* @param {years}
*/
export function getStatArea(params) {
return request({
method: 'GET',
url: `/api/marketsearchHome/statArea`,
params
})
}
// 受调查企业地域分布
/**
* @param {years}
*/
export function getCompanyPlace(params) {
return request({
method: 'GET',
url: `/api/marketsearchHome/getOrgDistribution`,
params
})
}
// 制裁领域分布-企业接口分布
/**
* @param {years}
*/
export function getStatAreaCompanyList() {
return request({
method: 'GET',
url: `/api/marketsearchHome/getOrgSanctionsDomain`,
})
}
// 资源库
// 左侧行业领域列表
export function getHylyList() {
return request({
method: 'GET',
url: `/api/billImpactAnalysis/industry/hylyList`,
})
}
// 获取调查列表接口
/**
* @param {currentPage, pageSize, sortCode, publishYear, Area, sortField, sortOrder}
*/
export function getSurveyList(params) {
return request({
method: 'GET',
url: `/api/marketsearchHome/statList`,
params
})
}
// 详情页---------------------------------------------------
// 获取调查列表接口
/**
* @param { sortCode }
*/
export function getSurvyInfo(params) {
return request({
method: 'GET',
url: `/api/marketsearchHome/statSortDetails`,
params
})
}
\ No newline at end of file
export const policyList = [
{
id: 1,
imageUrl: 'https://picsum.photos/60/80?random=101',
title: '允许OPT国际学生出境旅行并持多次入境签证重新进入美国。',
date: '2025年6月24日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['人才交流', '移民政策'],
status: 'implemented',
relatedBill: { text: '相关立法已通过:《2024值得关注的国会人口结构法案》' }
},
{
id: 2,
imageUrl: 'https://picsum.photos/60/80?random=102',
title: '增加中国公民可获得的 H-1B 签证数量。',
date: '2025年6月24日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['人才交流', '移民政策'],
status: 'unimplemented',
relatedBill: null
},
{
id: 3,
imageUrl: 'https://picsum.photos/60/80?random=103',
title: '通过职业偏好类别增加绿卡的数量。',
date: '2025年6月24日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['人才交流', '移民政策'],
status: 'partial',
relatedBill: { text: '存在相关提案:《2024调整签证以吸引国外顶尖人才法案》' }
},
{
id: 4,
imageUrl: 'https://picsum.photos/60/80?random=104',
title: '推动清洁能源生产的内用,化石燃料重新配置出口。',
date: '2025年6月24日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['能源政策', '环境保护'],
status: 'partial',
relatedBill: { text: '存在相关提案:《2024清洁能源转型促进法案》' }
},
{
id: 5,
imageUrl: 'https://picsum.photos/60/80?random=105',
title: '加强对关键技术出口的管制措施。',
date: '2025年6月24日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['技术安全', '出口管制'],
status: 'implemented',
relatedBill: { text: '相关立法已通过:《2024关键技术保护法案》' }
},
{
id: 6,
imageUrl: 'https://picsum.photos/60/80?random=106',
title: '建立多边技术合作框架,促进盟友间技术共享。',
date: '2025年6月23日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['国际合作', '技术共享'],
status: 'unimplemented',
relatedBill: null
},
{
id: 7,
imageUrl: 'https://picsum.photos/60/80?random=107',
title: '完善供应链韧性,减少对单一国家的依赖。',
date: '2025年6月23日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['供应链', '经济安全'],
status: 'partial',
relatedBill: { text: '存在相关提案:《2024供应链韧性提升法案》' }
},
{
id: 8,
imageUrl: 'https://picsum.photos/60/80?random=108',
title: '加大对新兴技术研发的投资力度。',
date: '2025年6月22日',
source: '中美经济竞争:复杂经济和地缘政治关系中的收益与风险',
tags: ['科技投资', '研发创新'],
status: 'implemented',
relatedBill: { text: '相关立法已通过:《2024科技创新投资法案》' }
}
]
export const corePersom = [
{
id: 1,
name: '杰森·马西尼',
position: '兰德公司总裁兼首席执行官',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face'
},
{
id: 2,
name: '安德鲁·R·霍恩',
position: '高级副总裁,研究与分析',
avatar: 'https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop&crop=face'
},
{
id: 3,
name: '杰森·马西尼',
position: '兰德公司总裁兼首席执行官',
avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop&crop=face'
},
{
id: 4,
name: '梅丽莎·罗',
position: '副总裁,全球研究人才政策分析数据政策分析政策学院',
avatar: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=100&h=100&fit=crop&crop=face'
},
{
id: 5,
name: '梅丽莎·罗',
position: '副总裁,全球研究人才政策分析数据政策分析政策学院',
avatar: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=100&h=100&fit=crop&crop=face'
},
{
id: 6,
name: '安妮塔·钱德拉',
position: '副总裁兼主任,兰德社会经济福利,高级政策研究员',
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face'
},
{
id: 7,
name: '安妮塔·钱德拉',
position: '兰德研究院研究员,兰德公司政策中心临时副总裁兼主任,工程和应用科学部',
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face'
},
{
id: 8,
name: '安妮塔·钱德拉',
position: '副总裁兼主任,兰德社会经济福利,高级政策研究员',
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face'
},
{
id: 9,
name: '梅丽莎·罗',
position: '副总裁,全球研究人才政策分析数据政策分析政策学院',
avatar: 'https://images.unsplash.com/photo-1494790108755-2616b612b786?w=100&h=100&fit=crop&crop=face'
},
{
id: 10,
name: '安妮塔·钱德拉',
position: '副总裁兼主任,兰德社会经济福利,高级政策研究员政策分析数据',
avatar: 'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=100&h=100&fit=crop&crop=face'
}
]
\ No newline at end of file
...@@ -202,6 +202,16 @@ export const getThinkTankReportSummary = (params) => { ...@@ -202,6 +202,16 @@ export const getThinkTankReportSummary = (params) => {
); );
} }
//获取报告原文
export const getThinkTankReportcontentUrl = (params) => {
return request(
{
method: 'GET',
url: `/api/thinkTankReport/contentUrl/${params}`,
}
);
}
//获取报告内容摘要 //获取报告内容摘要
export function getThinkTankReportAbstract(params) { export function getThinkTankReportAbstract(params) {
return request({ return request({
...@@ -230,7 +240,7 @@ export function getThinkTankReportIndustry(params) { ...@@ -230,7 +240,7 @@ export function getThinkTankReportIndustry(params) {
export function getThinkTankReportIndustryCloud(params) { export function getThinkTankReportIndustryCloud(params) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/thinkTankReport/industry/${params.id}/${params.industryId}`, url: `/api/thinkTankReport/keyword/${params.id}`,
}) })
} }
......
...@@ -2,33 +2,41 @@ ...@@ -2,33 +2,41 @@
import thinkTank from "@/views/thinkTank/index.vue"; import thinkTank from "@/views/thinkTank/index.vue";
import ThinkTankDetail from "@/views/thinkTank/ThinkTankDetail/index.vue"; import ThinkTankDetail from "@/views/thinkTank/ThinkTankDetail/index.vue";
import ReportDetail from "@/views/thinkTank/ReportDetail/index.vue"; import ReportDetail from "@/views/thinkTank/ReportDetail/index.vue";
import ReportOriginal from "@/views/thinkTank/reportOriginal/index.vue"
const thinktankRoutes = [ const thinktankRoutes = [
// 智库系统的主要路由 // 智库系统的主要路由
{ {
path: "/thinkTank", path: "/thinkTank",
name: "thinkTank", name: "thinkTank",
component: thinkTank, component: thinkTank,
meta: { meta: {
title: "首页" title: "首页"
} }
}, },
{ {
path: "/thinkTank/thinkTankDetail/:id", path: "/thinkTank/thinkTankDetail/:id",
name: "ThinkTankDetail", name: "ThinkTankDetail",
component: ThinkTankDetail, component: ThinkTankDetail,
meta: { meta: {
title: "智库详情" title: "智库详情"
} }
}, },
{ {
path: "/thinkTank/reportDetail/:id", path: "/thinkTank/reportDetail/:id",
name: "ReportDetail", name: "ReportDetail",
component: ReportDetail, component: ReportDetail,
meta: { meta: {
title: "报告详情" title: "报告详情"
} }
}, },
{
path: "/thinkTank/reportOriginal/:id",
name: "ReportOriginal",
component: ReportOriginal,
meta: {
title: "报告原文"
}
},
] ]
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
--btn-active-border-color: var(--color-main-active); --btn-active-border-color: var(--color-main-active);
--btn-active-bg-color: rgba(231, 243, 255, 1); --btn-active-bg-color: rgba(231, 243, 255, 1);
--btn-active-text-color: var(--color-main-active); --btn-active-text-color: var(--color-main-active);
/* 标签按钮颜色 */ /* 标签按钮颜色 */
--tag-btn1-bg-color: rgba(255, 241, 240, 1); --tag-btn1-bg-color: rgba(255, 241, 240, 1);
...@@ -31,4 +31,23 @@ ...@@ -31,4 +31,23 @@
--tag-btn3-border-color: rgba(217, 247, 190, 1); --tag-btn3-border-color: rgba(217, 247, 190, 1);
--tag-btn3-text-color: rgba(82, 196, 26, 1); --tag-btn3-text-color: rgba(82, 196, 26, 1);
} }
\ No newline at end of file
.hover-dialog {
max-width: 1200px;
max-height: 600px;
overflow: hidden;
overflow-y: auto;
padding: 8px 16px;
border-radius: 10px;
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(59, 65, 75, 1);
color: #fff;
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 16px;
font-weight: 400;
line-height: 30px;
letter-spacing: 0px;
text-align: left;
}
...@@ -678,7 +678,7 @@ ...@@ -678,7 +678,7 @@
</div> </div>
<div class="right-footer"> <div class="right-footer">
<div class="footer-left"> <div class="footer-left">
{{ `共${total}项调查` }} {{ `共 ${total} 条法案` }}
</div> </div>
<div class="footer-right"> <div class="footer-right">
<el-pagination <el-pagination
......
...@@ -67,6 +67,48 @@ ...@@ -67,6 +67,48 @@
class="content ai-content" class="content ai-content"
v-html="renderMarkdown(message.content)" v-html="renderMarkdown(message.content)"
></div> ></div>
<div v-if="message.raw_data" class="answer-title">完整实体列表</div>
<div v-if="message.raw_data" class="content row-content">
<div class="row-header">
<div class="row-header-item1">{{ message.raw_data.columns.name_zhs }}</div>
<div class="row-header-item">{{ message.raw_data.columns.date }}</div>
<div class="row-header-item">{{ message.raw_data.columns.industry }}</div>
<div class="row-header-item">{{ message.raw_data.columns.category }}</div>
<div class="row-header-item2">{{ message.raw_data.columns.sanction_reason }}</div>
</div>
<div class="row-main">
<div
class="row-main-item"
v-for="(item, index) in message.raw_data.rows"
:key="index"
>
<el-popover
effect="dark"
:width="500"
:content="item.name_zhs"
placement="top-start"
>
<template #reference>
<div class="item-item1">{{ item.name_zhs }}</div>
</template>
</el-popover>
<div class="item-item">{{ item.date }}</div>
<div class="item-item">{{ item.industry }}</div>
<div class="item-item">{{ item.category }}</div>
<el-popover
effect="dark"
:width="400"
:content="item.sanction_reason"
placement="top-start"
>
<template #reference>
<div class="item-item2">{{ item.sanction_reason }}</div>
</template>
</el-popover>
</div>
</div>
</div>
</div> </div>
<!-- 用户消息 --> <!-- 用户消息 -->
<div v-else class="user-item"> <div v-else class="user-item">
...@@ -175,17 +217,49 @@ const loadingDotIndex = ref(0); ...@@ -175,17 +217,49 @@ const loadingDotIndex = ref(0);
// 消息数据 // 消息数据
const messages = ref([ const messages = ref([
{ // {
type: "user", // type: "user",
content: "你好" // content: "你好"
}, // },
{ // {
type: "ai", // type: "ai",
source: [ // source: [
`完整检索实体名单: \n\n 中国科学院空天信息创新研究院\n\n北京复旦微电子技术有限公司\n\n北京天宜源生物科技有限公司\n\n北京擎科生物科技有限公司\n长沙南飞电子技术有限公司\n常州南飞微电子有限公司\n成都南飞微电子有限公司\n中国科学院国家授时中心\n吉姆西半导体科技(无锡)有限公司\n香港德铭电子有限公司\n华科物流(香港)有限公司\n华科供应链(香港)有限公司\n积村半导体科技(上海)有限公司\n生工生物工程(上海)股份有限公司\n上海复旦微电子集团股份有限公司\n上海复旦微电子(香港)有限公司\n上海富控华龙微电子系统技术有限公司\n上海富维迅捷数字科技有限公司\n上海索辰信息科技有限公司\n深圳复旦微电子有限公司\n深圳南飞微电子有限公司\n深圳新力康供应链管理有限公司\n盛美半导体设备(上海)股份有限公司\n总数量:23` // `完整检索实体名单: \n\n 中国科学院空天信息创新研究院\n\n北京复旦微电子技术有限公司\n\n北京天宜源生物科技有限公司\n\n北京擎科生物科技有限公司\n长沙南飞电子技术有限公司\n常州南飞微电子有限公司\n成都南飞微电子有限公司\n中国科学院国家授时中心\n吉姆西半导体科技(无锡)有限公司\n香港德铭电子有限公司\n华科物流(香港)有限公司\n华科供应链(香港)有限公司\n积村半导体科技(上海)有限公司\n生工生物工程(上海)股份有限公司\n上海复旦微电子集团股份有限公司\n上海复旦微电子(香港)有限公司\n上海富控华龙微电子系统技术有限公司\n上海富维迅捷数字科技有限公司\n上海索辰信息科技有限公司\n深圳复旦微电子有限公司\n深圳南飞微电子有限公司\n深圳新力康供应链管理有限公司\n盛美半导体设备(上海)股份有限公司\n总数量:23`
], // ],
content: `2025年9月实体清单的主要制裁实体、制裁原因\n\n 时间范围\n-当前查询的时间范围为:2025年9月16日。` // content: `2025年9月实体清单的主要制裁实体、制裁原因\n\n 时间范围\n-当前查询的时间范围为:2025年9月16日。`,
} // raw_data: {
// columns: {
// category: "实体类别",
// date: "制裁日期",
// industry: "所属行业",
// name_zhs: "实体名称",
// sanction_reason: "制裁理由"
// },
// rows: [
// {
// category: "科研机构",
// date: "2025-09-16",
// industry: "航空航天",
// name_zhs: "中国科学院空天信息创新研究院",
// sanction_reason: "与中国高空气球计划有关联"
// },
// {
// category: "科研机构",
// date: "2025-09-16",
// industry: "航空航天",
// name_zhs: "中国科学院空天信息创新研究院",
// sanction_reason: "与中国高空气球计划有关联"
// },
// {
// category: "科研机构",
// date: "2025-09-16",
// industry: "航空航天",
// name_zhs: "中国科学院空天信息创新研究院",
// sanction_reason: "与中国高空气球计划有关联"
// }
// ]
// }
// }
]); ]);
// Markdown 渲染器 // Markdown 渲染器
...@@ -419,6 +493,13 @@ const connectSSE = async question => { ...@@ -419,6 +493,13 @@ const connectSSE = async question => {
aiMessage.value += content; aiMessage.value += content;
updateLastAIMessage(aiMessage.value); updateLastAIMessage(aiMessage.value);
} }
if (msgData.raw_data) {
const lastMessage = messages.value[messages.value.length - 1];
if (lastMessage && lastMessage.type === "ai") {
lastMessage.raw_data = msgData.raw_data;
scrollToBottom();
}
}
// if (res.event === "end_of_workflow") { // if (res.event === "end_of_workflow") {
// ElMessage.success("问答完成!"); // ElMessage.success("问答完成!");
// abortController.value.abort(); // abortController.value.abort();
...@@ -703,6 +784,14 @@ const chat = async question => { ...@@ -703,6 +784,14 @@ const chat = async question => {
} }
} }
if (data.raw_data) {
const lastMessage = messages.value[messages.value.length - 1];
if (lastMessage && lastMessage.type === "ai") {
lastMessage.raw_data = data.raw_data;
scrollToBottom();
}
}
if (data.detail.error) { if (data.detail.error) {
console.log(data.detail.error.message); console.log(data.detail.error.message);
// ElMessage.error(data.detail.error.message); // ElMessage.error(data.detail.error.message);
...@@ -1144,6 +1233,78 @@ onUnmounted(() => { ...@@ -1144,6 +1233,78 @@ onUnmounted(() => {
padding: 1px 10px; padding: 1px 10px;
border-radius: 5px; border-radius: 5px;
} }
.row-content {
margin-top: 10px;
width: 900px;
margin-left: 26px;
background: rgba(246, 250, 255, 1);
padding: 1px 10px;
border-radius: 5px;
.row-header {
height: 40px;
line-height: 40px;
font-family: Microsoft-YaHei;
font-size: 20px;
color: #555;
font-weight: bold;
display: flex;
border-bottom: 1px solid #999;
.row-header-item {
text-align: center;
width: 150px;
border-right: 1px solid #999;
}
.row-header-item1 {
text-align: center;
width: 250px;
border-right: 1px solid #999;
}
.row-header-item2 {
text-align: center;
width: 200px;
}
}
.row-main {
padding-bottom: 10px;
.row-main-item {
height: 35px;
line-height: 35px;
font-family: Microsoft-YaHei;
font-size: 14px;
color: #555;
display: flex;
border-bottom: 1px solid #ccc;
.item-item {
width: 150px;
text-align: center;
border-right: 1px solid #ccc;
}
.item-item1 {
width: 250px;
text-align: center;
border-right: 1px solid #ccc;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
&:hover {
background: var(--color-bg-hover);
}
}
.item-item2 {
width: 200px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
&:hover {
background: var(--color-bg-hover);
}
}
}
}
}
} }
.user-item { .user-item {
margin-top: 32px; margin-top: 32px;
......
...@@ -256,7 +256,11 @@ ...@@ -256,7 +256,11 @@
<div class="title">{{ news.title }}</div> <div class="title">{{ news.title }}</div>
<div class="time">{{ news.from }}</div> <div class="time">{{ news.from }}</div>
</div> </div>
<div class="right-footer">{{ news.content }}</div> <el-popover effect="dark" :width="1000" :content="news.content" placement="top-start">
<template #reference>
<div class="right-footer">{{ news.content }}</div>
</template>
</el-popover>
</div> </div>
</div> </div>
</div> </div>
...@@ -270,7 +274,7 @@ ...@@ -270,7 +274,7 @@
</div> </div>
<div class="box4-main"> <div class="box4-main">
<div class="box4-main-item" v-for="(item, index) in messageList" :key="index"> <div class="box4-main-item" v-for="(item, index) in messageList" :key="index">
<div class="left" @click="handleClickPerson()"> <div class="left" @click="handleClickPerson(item)">
<img :src="item.img ? item.img : DefaultIcon1" alt="" /> <img :src="item.img ? item.img : DefaultIcon1" alt="" />
</div> </div>
<div class="right"> <div class="right">
...@@ -294,16 +298,12 @@ ...@@ -294,16 +298,12 @@
</div> </div>
<div class="box5-header-title">{{ "行政令发布频度" }}</div> <div class="box5-header-title">{{ "行政令发布频度" }}</div>
</div> </div>
</div>
<div class="box5-main">
<div class="box5-chart" id="chart1"></div>
<div class="box5-selectbox"> <div class="box5-selectbox">
<el-select <el-select
@change="handleBox5YearChange" @change="handleBox5YearChange"
v-model="box5SelectedYear" v-model="box5SelectedYear"
placeholder="选择时间" placeholder="选择时间"
style="width: 80px" style="width: 120px"
> >
<el-option <el-option
v-for="item in box5YearList" v-for="item in box5YearList"
...@@ -314,6 +314,10 @@ ...@@ -314,6 +314,10 @@
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="box5-main">
<div class="box5-chart" id="chart1"></div>
</div>
</div> </div>
<div class="box6"> <div class="box6">
<div class="box6-header"> <div class="box6-header">
...@@ -321,6 +325,21 @@ ...@@ -321,6 +325,21 @@
<img src="./assets/images/box4-header-icon.png" alt="" /> <img src="./assets/images/box4-header-icon.png" alt="" />
</div> </div>
<div class="header-title">{{ "政令涉及领域" }}</div> <div class="header-title">{{ "政令涉及领域" }}</div>
<div class="box6-selectbox">
<el-select
@change="handleBox6YearChange"
v-model="box6SelectedYear"
placeholder="选择时间"
style="width: 120px"
>
<el-option
v-for="item in box6YearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div> </div>
<div class="box6-main" id="chart2"></div> <div class="box6-main" id="chart2"></div>
</div> </div>
...@@ -334,7 +353,12 @@ ...@@ -334,7 +353,12 @@
<div class="header-title">{{ "关键行政令" }}</div> <div class="header-title">{{ "关键行政令" }}</div>
</div> </div>
<div class="box7-main"> <div class="box7-main">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index"> <div
class="box7-item"
v-for="(item, index) in keyDecreeList"
:key="index"
@click="handleKeyDecree(item.id)"
>
<div class="icon"> <div class="icon">
<img src="./assets/images/warning.png" alt="" /> <img src="./assets/images/warning.png" alt="" />
</div> </div>
...@@ -343,7 +367,11 @@ ...@@ -343,7 +367,11 @@
<div class="title">{{ item.title }}</div> <div class="title">{{ item.title }}</div>
<div class="time">{{ item.time }}</div> <div class="time">{{ item.time }}</div>
</div> </div>
<div class="info-content">{{ item.content ? item.content : "暂无数据" }}</div> <el-popover effect="dark" :width="800" :content="item.content" placement="top-start">
<template #reference>
<div class="info-content">{{ item.content ? item.content : "暂无数据" }}</div>
</template>
</el-popover>
</div> </div>
</div> </div>
</div> </div>
...@@ -394,7 +422,7 @@ ...@@ -394,7 +422,7 @@
:label="cate.name" :label="cate.name"
style="width: 180px" style="width: 180px"
class="filter-checkbox" class="filter-checkbox"
@change="handleChangeCheckedGovIns" @change="handleChangeCheckedGovIns"
> >
{{ cate.name }} {{ cate.name }}
</el-checkbox> </el-checkbox>
...@@ -489,7 +517,7 @@ ...@@ -489,7 +517,7 @@
</div> </div>
<div class="footer-box"> <div class="footer-box">
<div class="footer-left"> <div class="footer-left">
{{ `共${totalDecreesNum}项调查` }} {{ `共 ${totalDecreesNum} 条政令` }}
</div> </div>
<div class="footer-right"> <div class="footer-right">
<el-pagination <el-pagination
...@@ -524,6 +552,7 @@ import { ...@@ -524,6 +552,7 @@ import {
getDecreeOrderList, getDecreeOrderList,
getDecreehylyList getDecreehylyList
} from "@/api/decree/home"; } from "@/api/decree/home";
import { getPersonSummaryInfo } from "@/api/common/index";
import { getNews, getSocialMedia } from "@/api/general/index"; import { getNews, getSocialMedia } from "@/api/general/index";
import WordCloudMap from "./WordCloudMap.vue"; import WordCloudMap from "./WordCloudMap.vue";
import DivideHeader from "@/components/DivideHeader.vue"; import DivideHeader from "@/components/DivideHeader.vue";
...@@ -571,6 +600,7 @@ import News5 from "./assets/images/news5.png"; ...@@ -571,6 +600,7 @@ import News5 from "./assets/images/news5.png";
import Message1 from "./assets/images/message-icon1.png"; import Message1 from "./assets/images/message-icon1.png";
import Message2 from "./assets/images/message-icon2.png"; import Message2 from "./assets/images/message-icon2.png";
import Message3 from "./assets/images/message-icon3.png"; import Message3 from "./assets/images/message-icon3.png";
import { ElMessage } from "element-plus";
// 跳转行政机构主页 // 跳转行政机构主页
const handleToInstitution = item => { const handleToInstitution = item => {
...@@ -610,13 +640,9 @@ const govInsList = ref([ ...@@ -610,13 +640,9 @@ const govInsList = ref([
// name: "美国财政部" // name: "美国财政部"
// }, // },
]); ]);
const checkedGovIns = ref(['白宫']) const checkedGovIns = ref(["白宫"]);
const handleChangeCheckedGovIns = (val) => {
}
const handleChangeCheckedGovIns = val => {};
const handleGetDepartmentList = async () => { const handleGetDepartmentList = async () => {
try { try {
...@@ -719,26 +745,25 @@ const handleClickDecree = decree => { ...@@ -719,26 +745,25 @@ const handleClickDecree = decree => {
window.open(route.href, "_blank"); window.open(route.href, "_blank");
}; };
const handleKeyDecree = id => {
const route = router.resolve({
path: "/decreeLayout",
query: {
id: id
}
});
window.open(route.href, "_blank");
};
// 风险信号 // 风险信号
const warningList = ref([ const warningList = ref([
{ // {
id: 1, // id: 1,
name: "关于对中华人民共和国合成阿片类药物供应链...", // name: "关于对中华人民共和国合成阿片类药物供应链...",
postDate: "一天前", // postDate: "一天前",
riskLevel: "特别重大" // riskLevel: "特别重大"
}, // }
{
id: 2,
name: "关于调整钢铁进口的公告",
postDate: "一天前",
riskLevel: "重大风险"
},
{
id: 3,
name: "关于修订对中华人民共和国低价值进口商品适...",
postDate: "一天前",
riskLevel: "一般风险"
}
]); ]);
const handlegetDecreeRiskSignal = async () => { const handlegetDecreeRiskSignal = async () => {
try { try {
...@@ -828,22 +853,70 @@ const handleGetMessage = async () => { ...@@ -828,22 +853,70 @@ const handleGetMessage = async () => {
return { return {
img: item.personImage, img: item.personImage,
name: item.personName, name: item.personName,
time: item.time + " · 发布于" + item.orgName, time: item.time.replace("T", " ") + " · 发布于" + item.orgName,
content: item.remarks content: item.remarks,
personId: item.personId,
remarksId: item.remarksId
}; };
}); });
} catch (error) {} } catch (error) {}
}; };
handleGetMessage(); handleGetMessage();
// 点击人物头像,跳转到人物主页 // 点击人物头像,跳转到人物主页
const handleClickPerson = () => { const handleClickPerson = async item => {
const route = router.resolve({ console.log("person", item);
path: "/characterPage", const personTypeList = JSON.parse(window.sessionStorage.getItem("personTypeList"));
query: { console.log("personTypeList", personTypeList);
type: 3 // 1 2 3
let type = 0;
let personTypeName = "";
const params = {
personId: item.personId
};
try {
const res = await getPersonSummaryInfo(params);
console.log("人物全局信息", res);
if (res.code === 200 && res.data) {
const arr = personTypeList.filter(item => {
return item.typeId === res.data.personType;
});
console.log("arr", arr);
if (arr && arr.length > 0) {
personTypeName = arr[0].typeName;
console.log("personTypeName", personTypeName);
if (personTypeName === "科技企业领袖") {
type = 1;
} else if (personTypeName === "国会议员") {
type = 2;
} else if (personTypeName === "智库研究人员") {
type = 3;
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
return;
}
const route = router.resolve({
path: "/characterPage",
query: {
type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId: item.personId
}
});
window.open(route.href, "_blank");
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} else {
ElMessage.warning("找不到当前人员的类型值!");
return;
} }
}); } catch (error) {}
window.open(route.href, "_blank");
}; };
// 行政令发布频度 // 行政令发布频度
...@@ -919,9 +992,36 @@ const chart2Data = ref([ ...@@ -919,9 +992,36 @@ const chart2Data = ref([
]); ]);
// const colorList = ["#69B1FF", "#FFC069", "#87E8DE", "#85A5FF", "#FF7875", "#B37FEB", "#4096FF"]; // const colorList = ["#69B1FF", "#FFC069", "#87E8DE", "#85A5FF", "#FF7875", "#B37FEB", "#4096FF"];
const box6YearList = ref([
{
label: "2025",
value: "2025"
},
{
label: "2024",
value: "2024"
},
{
label: "2023",
value: "2023"
},
{
label: "2022",
value: "2022"
},
{
label: "2021",
value: "2021"
}
]);
const box6SelectedYear = ref("2025");
const handleGetDecreeArea = async () => { const handleGetDecreeArea = async () => {
const params = {
year: box6SelectedYear.value
};
try { try {
const res = await getDecreeArea(); const res = await getDecreeArea(params);
console.log("政令涉及领域", res); console.log("政令涉及领域", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
chart2Data.value = res.data.map(item => { chart2Data.value = res.data.map(item => {
...@@ -941,6 +1041,10 @@ const handleBox6 = async () => { ...@@ -941,6 +1041,10 @@ const handleBox6 = async () => {
setChart(chart2, "chart2"); setChart(chart2, "chart2");
}; };
const handleBox6YearChange = () => {
handleBox6();
};
// 关键行政令 // 关键行政令
const keyDecreeList = ref([ const keyDecreeList = ref([
// { // {
...@@ -964,7 +1068,8 @@ const handleGetKeyDecree = async () => { ...@@ -964,7 +1068,8 @@ const handleGetKeyDecree = async () => {
return { return {
title: item.name, title: item.name,
content: item.describe, content: item.describe,
time: item.postDate time: item.postDate,
id: item.orderId
}; };
}); });
} }
...@@ -1012,7 +1117,6 @@ const handleSwithSort = () => { ...@@ -1012,7 +1117,6 @@ const handleSwithSort = () => {
isSort.value = !isSort.value; isSort.value = !isSort.value;
}; };
const handleToPosi = id => { const handleToPosi = id => {
// 0 618 1240 2350 // 0 618 1240 2350
switch (id) { switch (id) {
...@@ -1060,7 +1164,8 @@ const pubTime = ref([ ...@@ -1060,7 +1164,8 @@ const pubTime = ref([
{ id: "2023", name: "2023年" }, { id: "2023", name: "2023年" },
{ id: "2022", name: "2022年" }, { id: "2022", name: "2022年" },
{ id: "2021", name: "2021年" }, { id: "2021", name: "2021年" },
{ id: "更早时间", name: "更早时间" } { id: "2020", name: "2020年" },
// { id: "更早时间", name: "更早时间" }
]); ]);
const activePubTime = ref(["2025"]); const activePubTime = ref(["2025"]);
...@@ -1088,7 +1193,7 @@ const decreeList = ref([ ...@@ -1088,7 +1193,7 @@ const decreeList = ref([
]); ]);
const handleGetDecreeOrderList = async () => { const handleGetDecreeOrderList = async () => {
const p0 = checkedGovIns.value.join(',') const p0 = checkedGovIns.value.join(",");
const p1 = activeAreaList.value.join(","); const p1 = activeAreaList.value.join(",");
const p2 = activePubTime.value.join(","); const p2 = activePubTime.value.join(",");
const params = { const params = {
...@@ -1109,7 +1214,7 @@ const handleGetDecreeOrderList = async () => { ...@@ -1109,7 +1214,7 @@ const handleGetDecreeOrderList = async () => {
id: item.id, id: item.id,
time: item.postDate, time: item.postDate,
title: item.name, title: item.name,
desc: item.order, desc: item.describe,
img: item.orgImage, img: item.orgImage,
tagList: item.industryList tagList: item.industryList
}; };
...@@ -1157,8 +1262,7 @@ watch( ...@@ -1157,8 +1262,7 @@ watch(
val => { val => {
handleGetDecreeOrderList(); handleGetDecreeOrderList();
} }
);
)
// 切换当前政令 // 切换当前政令
const handleSwithCurDecree = name => { const handleSwithCurDecree = name => {
...@@ -2555,26 +2659,13 @@ onMounted(async () => { ...@@ -2555,26 +2659,13 @@ onMounted(async () => {
line-height: 26px; line-height: 26px;
} }
} }
.box5-header-right { .box5-selectbox {
width: 49px; margin-right: 20px;
height: 24px; margin-top: 8px;
margin-top: 12px;
margin-right: 27px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
} }
} }
.box5-main { .box5-main {
height: 397px; height: 397px;
position: relative;
.box5-selectbox {
position: absolute;
right: 10px;
top: 10px;
}
.box5-chart { .box5-chart {
height: 397px; height: 397px;
} }
...@@ -2613,17 +2704,10 @@ onMounted(async () => { ...@@ -2613,17 +2704,10 @@ onMounted(async () => {
font-weight: 700; font-weight: 700;
line-height: 26px; line-height: 26px;
} }
.header-right { .box6-selectbox {
position: absolute; position: absolute;
right: 27px; right: 20px;
width: 49px; top: 8px;
height: 24px;
top: 12px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
} }
} }
.box6-main { .box6-main {
...@@ -2680,6 +2764,10 @@ onMounted(async () => { ...@@ -2680,6 +2764,10 @@ onMounted(async () => {
margin-top: 16px; margin-top: 16px;
margin-left: 25px; margin-left: 25px;
display: flex; display: flex;
cursor: pointer;
&:hover {
background: var(--color-bg-hover);
}
.icon { .icon {
margin-top: 6px; margin-top: 6px;
width: 24px; width: 24px;
...@@ -2778,7 +2866,8 @@ onMounted(async () => { ...@@ -2778,7 +2866,8 @@ onMounted(async () => {
} }
.home-main-footer { .home-main-footer {
margin-top: 34px; margin-top: 34px;
height: 1860px; max-height: 1860px;
padding-bottom: 160px;
background: rgba(248, 249, 250, 1); background: rgba(248, 249, 250, 1);
overflow: hidden; overflow: hidden;
.divide4 { .divide4 {
...@@ -2924,7 +3013,7 @@ onMounted(async () => { ...@@ -2924,7 +3013,7 @@ onMounted(async () => {
} }
.right { .right {
width: 1284px; width: 1284px;
height: 1489px; max-height: 1489px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
box-sizing: border-box; box-sizing: border-box;
...@@ -2955,7 +3044,7 @@ onMounted(async () => { ...@@ -2955,7 +3044,7 @@ onMounted(async () => {
} }
} }
.content-box { .content-box {
height: 1367px; max-height: 1367px;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
overflow: hidden; overflow: hidden;
.main-item { .main-item {
...@@ -3076,9 +3165,8 @@ onMounted(async () => { ...@@ -3076,9 +3165,8 @@ onMounted(async () => {
} }
} }
.footer-box { .footer-box {
margin: 0 30px; margin: 20px 30px;
height: 32px; height: 32px;
margin-top: 20px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.footer-left { .footer-left {
......
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
<div class="title">{{ "政令主要内容" }}</div> <div class="title">{{ "政令主要内容" }}</div>
</div> </div>
<div class="list-main"> <div class="list-main">
<div class="list-item" v-for="(val, idx) in showList" :key="idx"> <div class="list-item" v-for="(val, idx) in showList" :key="idx" @click="handleToDecreeDetail(val)">
<div class="id">{{ idx + 1 }}</div> <div class="id">{{ idx + 1 }}</div>
<div class="title">{{ val.content }}</div> <div class="title">{{ val.content }}</div>
<div class="open"> <div class="open">
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
<script setup> <script setup>
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import router from "@/router";
import { getDecreeMainContent } from "@/api/decree/introduction"; import { getDecreeMainContent } from "@/api/decree/introduction";
import { getDecreeRelateOrder } from "@/api/decree/deepdig"; import { getDecreeRelateOrder } from "@/api/decree/deepdig";
...@@ -254,6 +254,16 @@ const handleGetRelateOrder = async () => { ...@@ -254,6 +254,16 @@ const handleGetRelateOrder = async () => {
} }
}; };
const handleToDecreeDetail = (item) => {
const route = router.resolve({
path: "/decreeLayout/overview/introduction",
query: {
id: item.id
}
});
window.open(route.href, "_blank");
}
onMounted(() => { onMounted(() => {
handleGetRelateOrder(); handleGetRelateOrder();
}); });
...@@ -385,17 +395,17 @@ onMounted(() => { ...@@ -385,17 +395,17 @@ onMounted(() => {
background: rgba(246, 250, 255, 1); background: rgba(246, 250, 255, 1);
display: flex; display: flex;
.info-left { .info-left {
width: 97px; width: 242px;
height: 136px; height: 136px;
margin-top: 25px; margin-top: 25px;
margin-left: 28px; margin-left: 28px;
img { img {
width: 100%; width: 100%;
height: 100%; // height: 100%;
} }
} }
.info-right { .info-right {
margin-left: 35px; margin-left: 20px;
margin-top: 22px; margin-top: 22px;
.info-item { .info-item {
display: flex; display: flex;
...@@ -412,7 +422,7 @@ onMounted(() => { ...@@ -412,7 +422,7 @@ onMounted(() => {
line-height: 24px; line-height: 24px;
} }
.item-right { .item-right {
width: 899px; width: 769px;
height: 30px; height: 30px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -483,6 +493,10 @@ onMounted(() => { ...@@ -483,6 +493,10 @@ onMounted(() => {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex; display: flex;
cursor: pointer;
&:hover{
background: var(--color-bg-hover);
}
.id { .id {
width: 24px; width: 24px;
height: 24px; height: 24px;
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
<!-- <el-button type="plain" size="large" icon="Search" @click="handleSwitchActiveName('法案原文')" <!-- <el-button type="plain" size="large" icon="Search" @click="handleSwitchActiveName('法案原文')"
>政令原文</el-button >政令原文</el-button
> --> > -->
<el-button type="plain" size="large" icon="Search">政令原文</el-button> <el-button type="plain" size="large" icon="Search" @click="handleShowReport">政令原文</el-button>
<el-button type="primary" size="large" icon="EditPen">分析报告</el-button> <el-button type="primary" size="large" icon="EditPen">分析报告</el-button>
</div> </div>
</div> </div>
...@@ -106,17 +106,24 @@ ...@@ -106,17 +106,24 @@
</div> </div>
</div> </div>
</div> </div>
<!-- <div class="tool-box"> <div class="report" v-if="isShowReport">
<div class="tool1"> <div class="report-close" @click="handleCloseReport">
<img src="./assets/icons/tool-icon1.png" alt="" /> <img src="@/assets/icons/close.png" alt="" />
</div> </div>
<div class="tool2"> <div class="report-header">
<img src="./assets/icons/tool-icon2.png" alt="" /> {{ "政令原文" }}
</div> </div>
<div class="tool3"> <div class="report-main">
<img src="./assets/icons/tool-icon3.png" alt="" /> <div class="left">
</div> <div v-if="!reportUrl" class="noContent">{{ "中文原文暂无数据" }}</div>
</div> --> <iframe v-else :src="reportUrl" style="border: none" width="100%" height="100%"> </iframe>
</div>
<div class="right">
<div v-if="!reportUrlEn" class="noContent">{{ "英文原文暂无数据" }}</div>
<iframe v-else :src="reportUrlEn" style="border: none" width="100%" height="100%"> </iframe>
</div>
</div>
</div>
</div> </div>
</template> </template>
...@@ -125,6 +132,7 @@ import { ref, onMounted, onUnmounted } from "vue"; ...@@ -125,6 +132,7 @@ import { ref, onMounted, onUnmounted } from "vue";
import router from "@/router"; import router from "@/router";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getDecreeSummary } from "@/api/decree/introduction"; import { getDecreeSummary } from "@/api/decree/introduction";
import { getDecreeReport } from "@/api/decree/introduction";
import search from "./assets/images/search.png"; import search from "./assets/images/search.png";
import icon1 from "./assets/icons/icon1.png"; import icon1 from "./assets/icons/icon1.png";
...@@ -134,12 +142,16 @@ import icon2Active from "./assets/icons/icon2_active.png"; ...@@ -134,12 +142,16 @@ import icon2Active from "./assets/icons/icon2_active.png";
import icon3 from "./assets/icons/icon3.png"; import icon3 from "./assets/icons/icon3.png";
import icon3Active from "./assets/icons/icon3_active.png"; import icon3Active from "./assets/icons/icon3_active.png";
import DefaultIcon2 from '@/assets/icons/default-icon2.png' import DefaultIcon2 from "@/assets/icons/default-icon2.png";
const route = useRoute(); const route = useRoute();
const decreeId = ref(route.query.id); const decreeId = ref(route.query.id);
const isShowReport = ref(false);
const reportUrl = ref("");
const reportUrlEn = ref("");
const activeName = ref("分析报告"); const activeName = ref("分析报告");
const summaryInfo = ref({}); const summaryInfo = ref({});
...@@ -186,7 +198,6 @@ const activeTitle = ref("政令概况"); ...@@ -186,7 +198,6 @@ const activeTitle = ref("政令概况");
const handleClickMainHeaderBtn = item => { const handleClickMainHeaderBtn = item => {
activeTitle.value = item.name; activeTitle.value = item.name;
window.sessionStorage.setItem("activeTitle", item.name);
router.push({ router.push({
path: item.path, path: item.path,
query: { query: {
...@@ -209,26 +220,119 @@ const handleGetSummary = async () => { ...@@ -209,26 +220,119 @@ const handleGetSummary = async () => {
} catch (error) {} } catch (error) {}
}; };
// 获取报告原文
const handleGetReport = async () => {
const params = {
id: route.query.id
};
try {
const res = await getDecreeReport(params);
console.log("报告原文", res);
if (res.code === 200 && res.data) {
reportUrl.value = res.data.content;
reportUrlEn.value = res.data.contentEn;
}
} catch (error) {}
};
const handleCloseReport = () => {
isShowReport.value = false
}
const handleShowReport = () => {
isShowReport.value = true
}
onMounted(() => { onMounted(() => {
handleGetSummary(); handleGetSummary();
if (window.sessionStorage.getItem("activeTitle")) { console.log(route.path);
activeTitle.value = window.sessionStorage.getItem("activeTitle"); if (route.path === "/decreeLayout/overview/introduction" || route.path === "/decreeLayout/overview/background") {
activeTitle.value = "政令概况";
} else if (route.path === "/decreeLayout/deepDig") {
activeTitle.value = "政令概况";
} else {
activeTitle.value = "影响分析";
} }
handleGetReport()
}); });
onUnmounted(() => {
if (window.sessionStorage.getItem("activeTitle")) {
window.sessionStorage.removeItem("activeTitle");
}
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.layout-container { .layout-container {
width: 1920px; width: 100vw;
height: 1016px; height: 100vh;
min-width: 1920px;
min-height: 1016px;
background: rgba(249, 250, 252, 1); background: rgba(249, 250, 252, 1);
position: relative; position: relative;
.report {
padding: 10px 150px;
position: absolute;
left: 0;
top: 0;
z-index: 999999;
width: 100%;
height: 100%;
background: #f7f8f9;
.report-close {
position: absolute;
top: 20px;
right: 230px;
width: 20px;
height: 20px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.report-header {
width: 100%;
height: 50px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 20px;
font-weight: 700;
line-height: 50px;
letter-spacing: 0px;
text-align: left;
padding-left: 30px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
}
.report-main {
display: flex;
height: calc(100% - 100px);
justify-content: space-between;
.left {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
text-align: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
}
.right {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
text-align: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
}
}
}
.layout-main { .layout-main {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -247,7 +351,7 @@ onUnmounted(() => { ...@@ -247,7 +351,7 @@ onUnmounted(() => {
.icon { .icon {
width: 64px; width: 64px;
height: 64px; height: 64px;
img{ img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
......
...@@ -163,22 +163,22 @@ const handleScroll = () => { ...@@ -163,22 +163,22 @@ const handleScroll = () => {
}; };
onMounted(async () => { onMounted(async () => {
try { // try {
const chainFishboneData = await getChainFishbone(props.chainId); // const chainFishboneData = await getChainFishbone(props.chainId);
fishboneData.value = chainFishboneData?.causes ?? []; // fishboneData.value = chainFishboneData?.causes ?? [];
// 等待DOM更新后检查是否需要滚动 // // 等待DOM更新后检查是否需要滚动
nextTick(() => { // nextTick(() => {
if (scrollContainerRef.value && fishboneRef.value) { // if (scrollContainerRef.value && fishboneRef.value) {
showScrollIndicator.value = fishboneRef.value.scrollWidth > scrollContainerRef.value.clientWidth; // showScrollIndicator.value = fishboneRef.value.scrollWidth > scrollContainerRef.value.clientWidth;
updateScrollState(); // updateScrollState();
} // }
}); // });
console.log("鱼骨图数据:", fishboneData.value); // console.log("鱼骨图数据:", fishboneData.value);
} catch (error) { // } catch (error) {
console.log(error); // console.log(error);
} // }
}); });
// 监听props中的chainId变化 // 监听props中的chainId变化
......
...@@ -87,7 +87,7 @@ ...@@ -87,7 +87,7 @@
</div> </div>
</div> </div>
<div class="box2-main-main"> <div class="box2-main-main">
<Fishbone :chainId="2" /> <Fishbone :chainId="chainId" />
</div> </div>
<div class="box2-main-footer"> <div class="box2-main-footer">
<div class="box2-main-footer-left"> <div class="box2-main-footer-left">
...@@ -95,7 +95,13 @@ ...@@ -95,7 +95,13 @@
<div class="icon"> <div class="icon">
<img src="@/assets/icons/warning.png" alt="" /> <img src="@/assets/icons/warning.png" alt="" />
</div> </div>
<div class="text">{{ "中国企业45家(51.00%),受制裁5家(7.00%)" }}</div> <div class="text">
{{
`中国企业${chainInfo.upstreamInternalCount}家(${
Number(chainInfo.upstreamInternalRate * 100).toFixed(2)
}%),受制裁${chainInfo.upstreamEntityCount}家(${Number(chainInfo.upstreamEntityRate * 100).toFixed(2)}%)`
}}
</div>
</div> </div>
<div class="bottom">{{ "基础支撑" }}</div> <div class="bottom">{{ "基础支撑" }}</div>
</div> </div>
...@@ -104,7 +110,15 @@ ...@@ -104,7 +110,15 @@
<div class="icon"> <div class="icon">
<img src="@/assets/icons/warning.png" alt="" /> <img src="@/assets/icons/warning.png" alt="" />
</div> </div>
<div class="text">{{ "中国企业45家(51.00%),受制裁8家(7.00%)" }}</div> <div class="text">
{{
`中国企业${chainInfo.midstreamInternalCount}家(${
Number(chainInfo.midstreamInternalRate * 100).toFixed(2)
}%),受制裁${chainInfo.midstreamEntityCount}家(${
Number(chainInfo.midstreamEntityRate * 100).toFixed(2)
}%)`
}}
</div>
</div> </div>
<div class="bottom">{{ "软件算法" }}</div> <div class="bottom">{{ "软件算法" }}</div>
</div> </div>
...@@ -113,7 +127,15 @@ ...@@ -113,7 +127,15 @@
<div class="icon"> <div class="icon">
<img src="@/assets/icons/warning.png" alt="" /> <img src="@/assets/icons/warning.png" alt="" />
</div> </div>
<div class="text">{{ "中国企业45家(51.00%),受制裁8家(7.00%)" }}</div> <div class="text">
{{
`中国企业${chainInfo.downstreamInternalCount}家(${
Number(chainInfo.downstreamInternalRate * 100).toFixed(2)
}%),受制裁${chainInfo.downstreamEntityCount}家(${
Number(chainInfo.downstreamEntityRate * 100).toFixed(2)
}%)`
}}
</div>
</div> </div>
<div class="bottom">{{ "行业应用" }}</div> <div class="bottom">{{ "行业应用" }}</div>
</div> </div>
...@@ -132,6 +154,7 @@ import router from "@/router"; ...@@ -132,6 +154,7 @@ import router from "@/router";
import setChart from "@/utils/setChart"; import setChart from "@/utils/setChart";
import getBarChart from "./utils/barChart"; import getBarChart from "./utils/barChart";
import { getDecreeIndustry, getDecreehylyList, getDecreeCompany, getDecreeAction } from "@/api/decree/influence"; import { getDecreeIndustry, getDecreehylyList, getDecreeCompany, getDecreeAction } from "@/api/decree/influence";
import { getCnEntityOnChain, getChainFishbone, getChainInfoByDomainId, getChainStructure } from "@/api/exportControl";
const route = useRoute(); const route = useRoute();
...@@ -195,6 +218,8 @@ const handleClickBox1Btn = btn => { ...@@ -195,6 +218,8 @@ const handleClickBox1Btn = btn => {
box1BtnActiveName.value = btn.name; box1BtnActiveName.value = btn.name;
curAreaId.value = btn.id; curAreaId.value = btn.id;
handleGetCompanyListByArea(); handleGetCompanyListByArea();
handleGetCompanyListByArea();
handleGetChainId();
}; };
// 获取行业领域列表 // 获取行业领域列表
...@@ -207,6 +232,7 @@ const handleGetHylyList = async () => { ...@@ -207,6 +232,7 @@ const handleGetHylyList = async () => {
box1BtnActiveName.value = box1BtnList.value[0].name; box1BtnActiveName.value = box1BtnList.value[0].name;
curAreaId.value = box1BtnList.value[0].id; curAreaId.value = box1BtnList.value[0].id;
handleGetCompanyListByArea(); handleGetCompanyListByArea();
handleGetChainId();
} }
} catch (error) {} } catch (error) {}
}; };
...@@ -361,10 +387,56 @@ watch( ...@@ -361,10 +387,56 @@ watch(
} }
); );
const chainInfo = 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 chainId = ref(0);
// 根据领域id获取chainId
const handleGetChainId = async () => {
try {
const res = await getChainInfoByDomainId(curAreaId.value);
console.log("获取chainId", res);
if (res && res.length) {
chainId.value = res[0].id;
console.log("chainId", chainId.value);
handleGetChainInfoByChainId();
}
} catch (error) {
console.error("chainId error", error);
}
};
// 根据chainId获取chainInfo
const handleGetChainInfoByChainId = async () => {
try {
const res = await getCnEntityOnChain(chainId.value);
console.log("chainInfo", res);
if (res) {
chainInfo.value = res;
}
} catch (error) {
console.log("chainInfo error", error);
}
};
onMounted(() => { onMounted(() => {
handleGetChart1Data(); handleGetChart1Data();
handleGetHylyList(); handleGetHylyList();
handleGetAction(); // handleGetAction();
handelBox1(); handelBox1();
}); });
</script> </script>
...@@ -372,8 +444,9 @@ onMounted(() => { ...@@ -372,8 +444,9 @@ onMounted(() => {
<style lang="scss" scoped> <style lang="scss" scoped>
.wrapper { .wrapper {
width: 100%; width: 100%;
height: 879px; height: 100%;
display: flex; display: flex;
justify-content: center;
.box-header { .box-header {
display: flex; display: flex;
height: 48px; height: 48px;
......
<template> <template>
<div class="introduction-wrap"> <div class="introduction-wrap">
<div
class="hover-dialog"
:style="{ position: 'absolute', zIndex: 9999, top: `${mouseY - 220}px`, left: `${mouseX - 600}px` }"
v-if="isShowBox2Dialog"
>
{{ box2ContentAll }}
</div>
<div class="left"> <div class="left">
<div class="box1"> <div class="box1">
<div class="box-header"> <div class="box-header">
...@@ -29,13 +36,13 @@ ...@@ -29,13 +36,13 @@
<div class="box1-item" v-for="(item, index) in backgroundList" :key="index"> <div class="box1-item" v-for="(item, index) in backgroundList" :key="index">
<div class="id">{{ index + 1 }}</div> <div class="id">{{ index + 1 }}</div>
<div class="title">{{ item.content }}</div> <div class="title">{{ item.content }}</div>
<div class="open"> <!-- <div class="open">
<img src="./assets/images/open-icon.png" alt="" /> <img src="./assets/images/open-icon.png" alt="" />
</div> </div> -->
</div> </div>
</div> </div>
<div class="box1-footer"> <div class="box1-footer">
<div class="box1-footer-left">{{ `共计${backgroundListNum}指令` }}</div> <div class="box1-footer-left">{{ `共计${backgroundListNum}背景` }}</div>
<div class="box1-footer-right"> <div class="box1-footer-right">
<el-pagination :page-size="5" background layout="prev, pager, next" :total="backgroundListNum" /> <el-pagination :page-size="5" background layout="prev, pager, next" :total="backgroundListNum" />
</div> </div>
...@@ -61,7 +68,13 @@ ...@@ -61,7 +68,13 @@
</div> </div>
<div class="item-center"> <div class="item-center">
<div class="title">{{ item.title }}</div> <div class="title">{{ item.title }}</div>
<div class="content">{{ item.content }}</div> <el-popover effect="dark" :width="1000" :content="item.content" placement="top-start">
<template #reference>
<div class="content">
{{ item.content }}
</div>
</template>
</el-popover>
</div> </div>
<div class="item-right">{{ item.time }}</div> <div class="item-right">{{ item.time }}</div>
</div> </div>
...@@ -87,11 +100,11 @@ ...@@ -87,11 +100,11 @@
</div> </div>
</div> </div>
<div class="box3-main"> <div class="box3-main">
<div class="box3-item" v-for="(item, index) in laws" :key="index"> <div class="box3-item" v-for="(item, index) in laws" :key="index" @click="handleToBillDetail(item)">
<div class="id">{{ index + 1 }}</div> <div class="id">{{ index + 1 }}</div>
<div class="item-header"> <div class="item-header">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.title }}</div>
<div class="info">{{ item.info }}</div> <!-- <div class="info">{{ item.info }}</div> -->
</div> </div>
<div class="item-content">{{ item.content }}</div> <div class="item-content">{{ item.content }}</div>
</div> </div>
...@@ -104,6 +117,7 @@ ...@@ -104,6 +117,7 @@
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import router from "@/router";
import { getDecreeBackground, getDecreeRelatedEvent, getDecreeDepend } from "@/api/decree/background"; import { getDecreeBackground, getDecreeRelatedEvent, getDecreeDepend } from "@/api/decree/background";
import Img1 from "./assets/images/box2-img1.png"; import Img1 from "./assets/images/box2-img1.png";
...@@ -112,11 +126,16 @@ import Img3 from "./assets/images/box2-img3.png"; ...@@ -112,11 +126,16 @@ import Img3 from "./assets/images/box2-img3.png";
import Img4 from "./assets/images/box2-img4.png"; import Img4 from "./assets/images/box2-img4.png";
import Img5 from "./assets/images/box2-img5.png"; import Img5 from "./assets/images/box2-img5.png";
import { reduce } from "lodash"; import { reduce } from "lodash";
import Index from "../index.vue";
const route = useRoute(); const route = useRoute();
const decreeId = ref(route.query.id); const decreeId = ref(route.query.id);
// 基本鼠标位置
const mouseX = ref(0);
const mouseY = ref(0);
// 提出背景 // 提出背景
const box1BtnList = ref(["涉华背景", "全部背景"]); const box1BtnList = ref(["涉华背景", "全部背景"]);
const box1ActiveBtn = ref("涉华背景"); const box1ActiveBtn = ref("涉华背景");
...@@ -144,8 +163,8 @@ const handleGetBackground = async () => { ...@@ -144,8 +163,8 @@ const handleGetBackground = async () => {
const res = await getDecreeBackground(params); const res = await getDecreeBackground(params);
console.log("提出背景", res); console.log("提出背景", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
backgroundListNum.value = res.data.numberOfElements backgroundListNum.value = res.data.numberOfElements;
backgroundList.value = res.data.content backgroundList.value = res.data.content;
} else { } else {
backgroundListNum.value = 0; backgroundListNum.value = 0;
backgroundList.value = []; backgroundList.value = [];
...@@ -162,75 +181,87 @@ const relatedEvents = ref([ ...@@ -162,75 +181,87 @@ const relatedEvents = ref([
// "斯坦福大学《2025年人工智能指数报告》显示,中美顶尖AI模型在MMLU(大规模多任务语言理解)等主流基准测试中的性能...", // "斯坦福大学《2025年人工智能指数报告》显示,中美顶尖AI模型在MMLU(大规模多任务语言理解)等主流基准测试中的性能...",
// time: "2025-08-30" // time: "2025-08-30"
// } // }
]); ]);
const handleGetRelateEvents = async () => { const handleGetRelateEvents = async () => {
const params = { const params = {
id: decreeId.value id: decreeId.value
} };
try { try {
const res = await getDecreeRelatedEvent(params) const res = await getDecreeRelatedEvent(params);
console.log('相关事件', res); console.log("相关事件", res);
if(res.code === 200 && res.data) { if (res.code === 200 && res.data) {
relatedEvents.value = res.data.map( item => { relatedEvents.value = res.data.map(item => {
return { return {
image: '', image: item.imageUrl,
title: item.sjbt, title: item.sjbt,
content: item.sjnr, content: item.sjnr,
time: item.sjsj time: item.sjsj
} };
}) });
} else { } else {
relatedEvents.value = [] relatedEvents.value = [];
} }
} catch (error) { } catch (error) {}
};
}
}
// 法律依据 // 法律依据
const laws = ref([ const laws = ref([
// { {
// name: "《美国法典》", title: "《美国法典》",
// info: "第3编第301条", info: "第3编第301条",
// content: content:
// "允许总统通过行政命令(Executive Order)​​ 或其它书面形式授权行政部门或机构的负责人​(如国务卿、财政部长等)代行本属于总统的法定职能(由国会立法授予总统的职能)。" "允许总统通过行政命令(Executive Order)​​ 或其它书面形式授权行政部门或机构的负责人​(如国务卿、财政部长等)代行本属于总统的法定职能(由国会立法授予总统的职能)。"
// }, },
// { {
// name: "《出口管制改革法案》", title: "《出口管制改革法案》",
// info: "", info: "",
// content: content:
// "该法案授权政府出于国家安全和外交政策目的对特定技术、商品和软件的出口进行管制。确保AI技术不流向“对手国家”是其题中应有之义。" "该法案授权政府出于国家安全和外交政策目的对特定技术、商品和软件的出口进行管制。确保AI技术不流向“对手国家”是其题中应有之义。"
// } }
]); ]);
const handleGetLaws = async () => { const handleGetLaws = async () => {
const params = { const params = {
id: decreeId.value id: decreeId.value
} };
try { try {
const res = await getDecreeDepend(params) const res = await getDecreeDepend(params);
console.log('法律依据', res); console.log("法律依据", res);
if(res.code === 200 && res.data) { if (res.code === 200 && res.data) {
laws.value = res.data;
} else { } else {
laws.value = [] laws.value = [];
} }
} catch (error) { } catch (error) {}
};
} const isShowBox2Dialog = ref(false);
} const box2ContentAll = ref("");
const handleChangeShowBox2Dialog = (isShow, content) => {
isShowBox2Dialog.value = isShow;
box2ContentAll.value = content;
};
const handleMouseMove = event => {
mouseX.value = event.screenX;
mouseY.value = event.screenY;
};
const handleToBillDetail = item => {
window.sessionStorage.setItem("billId", item.billId);
const route = router.resolve("/billLayout");
window.open(route.href, "_blank");
};
onMounted(() => { onMounted(() => {
handleGetBackground(); handleGetBackground();
handleGetRelateEvents() handleGetRelateEvents();
handleGetLaws() handleGetLaws();
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.introduction-wrap { .introduction-wrap {
display: flex; display: flex;
position: relative;
.box-header { .box-header {
height: 56px; height: 56px;
display: flex; display: flex;
...@@ -297,28 +328,32 @@ onMounted(() => { ...@@ -297,28 +328,32 @@ onMounted(() => {
} }
} }
.left { .left {
width: 1150px; width: 1064px;
.box1 { .box1 {
margin-top: 16px; margin-top: 16px;
width: 1150px; width: 1064px;
height: 414px; height: 414px;
border-radius: 4px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.box1-main { .box1-main {
margin-left: 22px; margin-left: 22px;
height: 280px; width: 1034px;
height: 290px;
overflow: hidden;
overflow-y: auto;
.box1-item { .box1-item {
width: 1101px; width: 1015px;
height: 48px; min-height: 48px;
margin-bottom: 8px; margin-bottom: 8px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1); border: 1px solid rgba(234, 236, 238, 1);
border-radius: 2px; border-radius: 2px;
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
display: flex; display: flex;
align-items: center;
padding: 8px 0;
.id { .id {
margin-top: 12px;
margin-left: 15px; margin-left: 15px;
width: 24px; width: 24px;
height: 24px; height: 24px;
...@@ -329,9 +364,12 @@ onMounted(() => { ...@@ -329,9 +364,12 @@ onMounted(() => {
color: #0a57a6; color: #0a57a6;
} }
.title { .title {
width: 1000px; width: 914px;
line-height: 48px; line-height: 24px;
margin-left: 13px; margin-left: 13px;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
} }
.open { .open {
width: 16px; width: 16px;
...@@ -360,16 +398,16 @@ onMounted(() => { ...@@ -360,16 +398,16 @@ onMounted(() => {
} }
.box2 { .box2 {
margin-top: 16px; margin-top: 16px;
width: 1150px; width: 1064px;
height: 415px; height: 415px;
border-radius: 4px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.box2-main { .box2-main {
margin-top: 3px; margin-top: 3px;
margin-left: 31px; margin-left: 31px;
height: 330px; height: 330px;
width: 1090px; width: 1004px;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
.box2-item { .box2-item {
...@@ -386,7 +424,7 @@ onMounted(() => { ...@@ -386,7 +424,7 @@ onMounted(() => {
} }
} }
.item-center { .item-center {
width: 892px; width: 806px;
margin-left: 14px; margin-left: 14px;
.title { .title {
height: 30px; height: 30px;
...@@ -398,7 +436,7 @@ onMounted(() => { ...@@ -398,7 +436,7 @@ onMounted(() => {
margin-top: -5px; margin-top: -5px;
} }
.content { .content {
width: 892px; width: 806px;
height: 30px; height: 30px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -408,6 +446,7 @@ onMounted(() => { ...@@ -408,6 +446,7 @@ onMounted(() => {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
cursor: pointer;
} }
} }
.item-right { .item-right {
...@@ -438,24 +477,28 @@ onMounted(() => { ...@@ -438,24 +477,28 @@ onMounted(() => {
margin-left: 16px; margin-left: 16px;
.box3 { .box3 {
margin-top: 16px; margin-top: 16px;
width: 576px; width: 520px;
height: 845px; height: 845px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.box3-main { .box3-main {
margin-top: 9px; margin-top: 9px;
width: 520px; width: 464px;
height: 720px; height: 720px;
// overflow: hidden;
overflow-y: auto; overflow-y: auto;
padding-left: 20px;
.box3-item { .box3-item {
margin-bottom: 24px; margin-bottom: 20px;
position: relative; position: relative;
cursor: pointer;
// border-bottom: 1px solid rgba(234, 236, 238, 1);
.id { .id {
width: 24px; width: 24px;
height: 24px; height: 24px;
position: absolute; position: absolute;
left: 28px; left: 18px;
top: 1px; top: 1px;
z-index: 99; z-index: 99;
text-align: center; text-align: center;
...@@ -466,13 +509,16 @@ onMounted(() => { ...@@ -466,13 +509,16 @@ onMounted(() => {
color: #0a57a6; color: #0a57a6;
} }
.item-header { .item-header {
width: 460px; width: 384px;
height: 35px; height: 35px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-left: 60px; margin-left: 60px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.name { .name {
max-width: 460px; max-width: 384px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref, onMounted, onUnmounted } from "vue"; import { ref, onMounted } from "vue";
import router from "@/router"; import router from "@/router";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
const route = useRoute(); const route = useRoute();
...@@ -41,7 +41,6 @@ const siderList = ref([ ...@@ -41,7 +41,6 @@ const siderList = ref([
const siderBtnActive = ref("政令简介"); const siderBtnActive = ref("政令简介");
const handleClickLeftSiderBtn = item => { const handleClickLeftSiderBtn = item => {
window.sessionStorage.setItem("siderBarActiveName", item.name);
siderBtnActive.value = item.name; siderBtnActive.value = item.name;
router.push({ router.push({
path: item.path, path: item.path,
...@@ -52,25 +51,22 @@ const handleClickLeftSiderBtn = item => { ...@@ -52,25 +51,22 @@ const handleClickLeftSiderBtn = item => {
}; };
onMounted(() => { onMounted(() => {
if (window.sessionStorage.getItem("siderBarActiveName")) { if (route.path === "/decreeLayout/overview/introduction") {
siderBtnActive.value = window.sessionStorage.getItem("siderBarActiveName"); siderBtnActive.value = "政令简介";
} } else {
}); siderBtnActive.value = "政令背景";
onUnmounted(() => {
if (window.sessionStorage.getItem("siderBarActiveName")) {
window.sessionStorage.removeItem("siderBarActiveName");
} }
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.decree-overview-wrap { .decree-overview-wrap {
width: 1920px; width: 100%;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
background: rgba(247, 248, 249, 1); background: rgba(247, 248, 249, 1);
display: flex; display: flex;
justify-content: center;
.left { .left {
width: 160px; width: 160px;
padding-top: 16px; padding-top: 16px;
......
...@@ -26,9 +26,16 @@ ...@@ -26,9 +26,16 @@
</div> </div>
<div class="item"> <div class="item">
<div class="item-left">{{ "英文全称:" }}</div> <div class="item-left">{{ "英文全称:" }}</div>
<div class="item-right text"> <div class="item-right text" v-if="basicInfo.eName?.length < 60">
{{ basicInfo.eName }} {{ basicInfo.eName }}
</div> </div>
<el-popover v-else effect="dark" :width="500" :content="basicInfo.eName" placement="top-start">
<template #reference>
<div class="item-right text">
{{ basicInfo.eName }}
</div>
</template>
</el-popover>
</div> </div>
<div class="item"> <div class="item">
<div class="item-left">{{ "相关领域:" }}</div> <div class="item-left">{{ "相关领域:" }}</div>
...@@ -43,9 +50,9 @@ ...@@ -43,9 +50,9 @@
<div class="item-right text">{{ basicInfo.signTime }}</div> <div class="item-right text">{{ basicInfo.signTime }}</div>
</div> </div>
<div class="item"> <div class="item">
<div class="item-left">{{ "签署总统:" }}</div> <div class="item-left">{{ "发布机构:" }}</div>
<div class="item-right text"> <div class="item-right text">
{{ basicInfo.signPeople }} {{ basicInfo.proposeOrgName }}
</div> </div>
</div> </div>
<div class="item"> <div class="item">
...@@ -80,9 +87,9 @@ ...@@ -80,9 +87,9 @@
<div class="box2-item" v-for="(item, index) in curmajorList" :key="index"> <div class="box2-item" v-for="(item, index) in curmajorList" :key="index">
<div class="id">{{ index + 1 }}</div> <div class="id">{{ index + 1 }}</div>
<div class="title">{{ item.content }}</div> <div class="title">{{ item.content }}</div>
<div class="open"> <!-- <div class="open">
<img src="./assets/images/open-icon.png" alt="" /> <img src="./assets/images/open-icon.png" alt="" />
</div> </div> -->
</div> </div>
</div> </div>
<div class="box2-footer"> <div class="box2-footer">
...@@ -127,7 +134,7 @@ ...@@ -127,7 +134,7 @@
<div class="box3-top"> <div class="box3-top">
<div class="box3-top-top"> <div class="box3-top-top">
<div class="left"> <div class="left">
<img :src="box3TopData.logo?box3TopData.logo:DefaultIcon2" alt="" /> <img :src="box3TopData.logo ? box3TopData.logo : DefaultIcon2" alt="" />
</div> </div>
<div class="right"> <div class="right">
<div class="name">{{ box3TopData.name }}</div> <div class="name">{{ box3TopData.name }}</div>
...@@ -199,11 +206,10 @@ import box1Img from "./assets/images/box1-img.png"; ...@@ -199,11 +206,10 @@ import box1Img from "./assets/images/box1-img.png";
import Box3Logo from "./assets/images/box3-img.png"; import Box3Logo from "./assets/images/box3-img.png";
import { getDecreeBasicInfo, getDecreeMainContent, getDecreeOrganization } from "@/api/decree/introduction"; import { getDecreeBasicInfo, getDecreeMainContent, getDecreeOrganization } from "@/api/decree/introduction";
import DefaultIcon1 from '@/assets/icons/default-icon1.png' import DefaultIcon1 from "@/assets/icons/default-icon1.png";
import DefaultIcon2 from '@/assets/icons/default-icon2.png' import DefaultIcon2 from "@/assets/icons/default-icon2.png";
const route = useRoute(); const route = useRoute();
const decreeId = ref(route.query.id); const decreeId = ref(route.query.id);
// 基本信息 // 基本信息
...@@ -233,6 +239,7 @@ const handleGetBasicInfo = async () => { ...@@ -233,6 +239,7 @@ const handleGetBasicInfo = async () => {
basicInfo.value.signTime = res.data.postDate; basicInfo.value.signTime = res.data.postDate;
basicInfo.value.bh = res.data.order; basicInfo.value.bh = res.data.order;
basicInfo.value.deadline = res.data.deadline; basicInfo.value.deadline = res.data.deadline;
basicInfo.value.proposeOrgName = res.data.proposeOrgName;
} }
} catch (error) { } catch (error) {
console.error("基本信息error", error); console.error("基本信息error", error);
...@@ -287,7 +294,6 @@ const box3BtnActiveIndex = ref(0); ...@@ -287,7 +294,6 @@ const box3BtnActiveIndex = ref(0);
const handleClickBox3Btn = (btn, index) => { const handleClickBox3Btn = (btn, index) => {
box3ActiveBtn.value = btn; box3ActiveBtn.value = btn;
box3BtnActiveIndex.value = index; box3BtnActiveIndex.value = index;
box3TopData.value.logo = box3Data.value[index].url; box3TopData.value.logo = box3Data.value[index].url;
box3TopData.value.name = box3Data.value[index].name; box3TopData.value.name = box3Data.value[index].name;
box3TopData.value.eName = box3Data.value[index].ename; box3TopData.value.eName = box3Data.value[index].ename;
...@@ -297,7 +303,7 @@ const handleClickBox3Btn = (btn, index) => { ...@@ -297,7 +303,7 @@ const handleClickBox3Btn = (btn, index) => {
eventList.value = box3Data.value[index].newsList.map(val => { eventList.value = box3Data.value[index].newsList.map(val => {
return { return {
time: val.newsDate, time: val.newsDate,
title: val.newsTitle title: val.newsContent
}; };
}); });
}; };
...@@ -327,7 +333,6 @@ const eventList = ref([ ...@@ -327,7 +333,6 @@ const eventList = ref([
// time: "2025-07-21", // time: "2025-07-21",
// title: "美商务部进一步收紧对华先进半导体出口管制,将更多中国实体列入“实体清单”。限制14纳米及以下先进芯片、DRAM等对华出口" // title: "美商务部进一步收紧对华先进半导体出口管制,将更多中国实体列入“实体清单”。限制14纳米及以下先进芯片、DRAM等对华出口"
// } // }
]); ]);
const handleGetOrgnization = async () => { const handleGetOrgnization = async () => {
...@@ -384,10 +389,8 @@ const handleGetOrgnization = async () => { ...@@ -384,10 +389,8 @@ const handleGetOrgnization = async () => {
}; };
onMounted(() => { onMounted(() => {
handleGetOrgnization(); handleGetOrgnization();
}) });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -416,12 +419,18 @@ handleGetOrgnization(); ...@@ -416,12 +419,18 @@ handleGetOrgnization();
} }
.header-btn-box { .header-btn-box {
position: absolute; position: absolute;
z-index: 9999;
width: 320px;
height: 56px;
top: 14px; top: 14px;
right: 84px; right: 84px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
flex-wrap: wrap;
gap: 8px; gap: 8px;
white-space: nowrap;
.btn { .btn {
min-width: min-content;
height: 28px; height: 28px;
padding: 0 8px; padding: 0 8px;
box-sizing: border-box; box-sizing: border-box;
...@@ -459,10 +468,10 @@ handleGetOrgnization(); ...@@ -459,10 +468,10 @@ handleGetOrgnization();
} }
} }
.left { .left {
width: 1150px; width: 1064px;
.box1 { .box1 {
margin-top: 16px; margin-top: 16px;
width: 1150px; width: 1064px;
height: 414px; height: 414px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
...@@ -470,16 +479,17 @@ handleGetOrgnization(); ...@@ -470,16 +479,17 @@ handleGetOrgnization();
.box1-main { .box1-main {
display: flex; display: flex;
.box1-main-left { .box1-main-left {
width: 235px; width: 395px;
height: 332px; height: 332px;
margin-left: 42px; margin-left: 42px;
img { img {
width: 100%; width: 100%;
height: 100%; // height: 100%;
} }
} }
.box1-main-right { .box1-main-right {
margin-left: 40px; width: 590px;
margin-left: 20px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
...@@ -492,6 +502,12 @@ handleGetOrgnization(); ...@@ -492,6 +502,12 @@ handleGetOrgnization();
.item-left { .item-left {
width: 100px; width: 100px;
} }
.item-right {
width: 470px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tag-box { .tag-box {
display: flex; display: flex;
.tag { .tag {
...@@ -518,7 +534,7 @@ handleGetOrgnization(); ...@@ -518,7 +534,7 @@ handleGetOrgnization();
} }
.box2 { .box2 {
margin-top: 16px; margin-top: 16px;
width: 1150px; width: 1064px;
height: 415px; height: 415px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
...@@ -526,20 +542,23 @@ handleGetOrgnization(); ...@@ -526,20 +542,23 @@ handleGetOrgnization();
.box2-main { .box2-main {
margin-left: 22px; margin-left: 22px;
height: 280px; height: 280px;
overflow: hidden;
overflow-y: auto;
.box2-item { .box2-item {
width: 1101px; width: 1015px;
height: 48px; // height: 48px;
margin-bottom: 8px; margin-bottom: 8px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1); border: 1px solid rgba(234, 236, 238, 1);
border-radius: 2px; border-radius: 2px;
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
display: flex; display: flex;
align-items: center;
padding: 12px 0;
&:nth-child(2n-1) { &:nth-child(2n-1) {
background: rgba(247, 248, 249, 1); background: rgba(247, 248, 249, 1);
} }
.id { .id {
margin-top: 12px;
margin-left: 15px; margin-left: 15px;
width: 24px; width: 24px;
height: 24px; height: 24px;
...@@ -551,15 +570,15 @@ handleGetOrgnization(); ...@@ -551,15 +570,15 @@ handleGetOrgnization();
} }
.title { .title {
width: 1020px; width: 1020px;
line-height: 48px; line-height: 24px;
margin-left: 5px; margin-left: 10px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 700; font-weight: 700;
overflow: hidden; // overflow: hidden;
text-overflow: ellipsis; // text-overflow: ellipsis;
white-space: nowrap; // white-space: nowrap;
} }
.open { .open {
width: 16px; width: 16px;
...@@ -588,17 +607,18 @@ handleGetOrgnization(); ...@@ -588,17 +607,18 @@ handleGetOrgnization();
} }
} }
.right { .right {
width: 520px;
margin-left: 16px; margin-left: 16px;
.box3 { .box3 {
margin-top: 16px; margin-top: 16px;
width: 576px; width: 520px;
height: 845px; height: 845px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.box3-top { .box3-top {
margin-top: 10px; margin-top: 30px;
height: 261px; height: 241px;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
.box3-top-top { .box3-top-top {
width: 473px; width: 473px;
...@@ -644,6 +664,7 @@ handleGetOrgnization(); ...@@ -644,6 +664,7 @@ handleGetOrgnization();
} }
} }
.right { .right {
width: 350px;
margin-left: 22px; margin-left: 22px;
.name { .name {
height: 26px; height: 26px;
...@@ -667,6 +688,9 @@ handleGetOrgnization(); ...@@ -667,6 +688,9 @@ handleGetOrgnization();
.box3-top-bottom { .box3-top-bottom {
margin-left: 50px; margin-left: 50px;
.box3-top-right-main { .box3-top-right-main {
height: 150px;
overflow: hidden;
overflow-y: auto;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
...@@ -676,7 +700,7 @@ handleGetOrgnization(); ...@@ -676,7 +700,7 @@ handleGetOrgnization();
.main-item { .main-item {
display: flex; display: flex;
margin-top: 12px; margin-top: 12px;
height: 26px; // height: 26px;
line-height: 26px; line-height: 26px;
.item-icon { .item-icon {
width: 4px; width: 4px;
...@@ -738,5 +762,72 @@ handleGetOrgnization(); ...@@ -738,5 +762,72 @@ handleGetOrgnization();
} }
} }
} }
.report {
padding: 10px 150px;
position: absolute;
left: 0;
top: 0;
z-index: 999999;
width: 100%;
height: 100%;
background: #f7f8f9;
.report-close {
position: absolute;
top: 20px;
right: 230px;
width: 20px;
height: 20px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.report-header {
width: 100%;
height: 50px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 20px;
font-weight: 700;
line-height: 50px;
letter-spacing: 0px;
text-align: left;
padding-left: 30px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
}
.report-main {
display: flex;
height: calc(100% - 100px);
justify-content: space-between;
.left {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
text-align: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
}
.right {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
text-align: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
}
}
}
} }
</style> </style>
\ No newline at end of file
...@@ -159,7 +159,7 @@ import getPieChart from "./utils/piechart"; ...@@ -159,7 +159,7 @@ import getPieChart from "./utils/piechart";
import getWordCloudChart from "./utils/worldCloudChart"; import getWordCloudChart from "./utils/worldCloudChart";
import getGraphChart from "./utils/graph"; import getGraphChart from "./utils/graph";
import { getGovOrgCompanyArea, getGovOrgOpinions } from "@/api/institution/index"; import { getGovOrgCompanyArea, getGovOrgOpinions, getPersonRelation } from "@/api/institution/index";
import Img from "./assets/images/9.png"; import Img from "./assets/images/9.png";
import Img1 from "./assets/images/1.png"; import Img1 from "./assets/images/1.png";
...@@ -171,7 +171,7 @@ import Img6 from "./assets/images/6.png"; ...@@ -171,7 +171,7 @@ import Img6 from "./assets/images/6.png";
import Img7 from "./assets/images/7.png"; import Img7 from "./assets/images/7.png";
import Img8 from "./assets/images/8.png"; import Img8 from "./assets/images/8.png";
const route = useRoute() const route = useRoute();
const box1ChartData = ref({ const box1ChartData = ref({
nodes: [ nodes: [
...@@ -381,19 +381,15 @@ const box3ChartData = ref([ ...@@ -381,19 +381,15 @@ const box3ChartData = ref([
]); ]);
const handleGetOpinions = async () => { const handleGetOpinions = async () => {
const params = { const params = {
orgId: '50754570da464d0a81a5563dcb61d2ec' orgId: "50754570da464d0a81a5563dcb61d2ec"
} };
try { try {
const res = await getGovOrgOpinions(params) const res = await getGovOrgOpinions(params);
console.log('主要科技政策观点', res); console.log("主要科技政策观点", res);
} catch (error) {}
} catch (error) { };
}
}
// 人物关系
const box4ChartData = ref({ const box4ChartData = ref({
nodes: [ nodes: [
{ id: "9", name: "霍华德·卢特尼克", category: 0, symbolSize: 50, symbol: `image://${Img}` }, { id: "9", name: "霍华德·卢特尼克", category: 0, symbolSize: 50, symbol: `image://${Img}` },
...@@ -418,18 +414,42 @@ const box4ChartData = ref({ ...@@ -418,18 +414,42 @@ const box4ChartData = ref({
], ],
categories: [{ name: "a" }, { name: "b" }] categories: [{ name: "a" }, { name: "b" }]
}); });
const handleGetPerosonRelation = async () => {
const params = {
orgId: route.query.id
};
try {
const res = await getPersonRelation(params);
console.log("人物关系", res);
if (res.code === 200 && res.data && res.data.length) {
} else {
box4ChartData.value.nodes = [];
box4ChartData.value.links = [];
box4ChartData.value.categories = [];
}
} catch (error) {
box4ChartData.value.nodes = [];
box4ChartData.value.links = [];
box4ChartData.value.categories = [];
}
};
const handleBox4 = async () => {
await handleGetPerosonRelation();
const box4Chart = getGraphChart(box4ChartData.value);
setChart(box4Chart, "box4Chart");
};
onMounted(() => { onMounted(() => {
handleBox2(); handleBox2();
handleGetOpinions() handleGetOpinions();
const box1Chart = getSankeyChart(box1ChartData.value.nodes, box1ChartData.value.links); const box1Chart = getSankeyChart(box1ChartData.value.nodes, box1ChartData.value.links);
setChart(box1Chart, "box1Chart"); setChart(box1Chart, "box1Chart");
const box3Chart = getWordCloudChart(box3ChartData.value); const box3Chart = getWordCloudChart(box3ChartData.value);
setChart(box3Chart, "box3Chart"); setChart(box3Chart, "box3Chart");
const box4Chart = getGraphChart(box4ChartData.value); handleBox4();
setChart(box4Chart, "box4Chart");
}); });
</script> </script>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="wrap"> <div class="wrap">
<div class="header"> <div class="header">
<div class="header-left"> <div class="header-left">
<img :src="institutionInfo.logo?institutionInfo.logo: DefaultIcon2" alt="" /> <img :src="institutionInfo.logo ? institutionInfo.logo : DefaultIcon2" alt="" />
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="title">{{ institutionInfo.name }}</div> <div class="title">{{ institutionInfo.name }}</div>
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
<div class="tab-box"> <div class="tab-box">
<div <div
class="tab" class="tab"
@click="handleClickTab(item, index)" @click="handleClickTab(item)"
:class="{ tabActive: item.active }" :class="{ tabActive: activeTabName == item.name }"
v-for="(item, index) in tabList" v-for="(item, index) in tabList"
:key="index" :key="index"
> >
...@@ -41,70 +41,72 @@ ...@@ -41,70 +41,72 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted, onUnmounted } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import InsDetail from "./insDetail/index.vue"; import InsDetail from "./insDetail/index.vue";
import Deepdig from "./deepdig/index.vue"; import Deepdig from "./deepdig/index.vue";
import Sanction from "./sanction/index.vue"; import Sanction from "./sanction/index.vue";
import {getGovOrgBasicInfo} from '@/api/institution/index' import { getGovOrgBasicInfo } from "@/api/institution/index";
import DefaultIcon2 from '@/assets/icons/default-icon2.png' import DefaultIcon2 from "@/assets/icons/default-icon2.png";
const route = useRoute() const route = useRoute();
const institutionInfo = ref({ const institutionInfo = ref({
name: "", name: "",
enName: "", enName: "",
desc: "", desc: "",
tagList: [], tagList: [],
logo: '' logo: ""
}); });
const handleGetInfo = async () => { const handleGetInfo = async () => {
const params = { const params = {
id: route.query.id id: route.query.id
} };
try { try {
const res = await getGovOrgBasicInfo(params) const res = await getGovOrgBasicInfo(params);
console.log('机构信息', res); console.log("机构信息", res);
if(res.code === 200 && res.data) { if (res.code === 200 && res.data) {
institutionInfo.value.name = res.data.orgName institutionInfo.value.name = res.data.orgName;
institutionInfo.value.enName = res.data.orgNameEn institutionInfo.value.enName = res.data.orgNameEn;
institutionInfo.value.desc = res.data.orgIntroduction institutionInfo.value.desc = res.data.orgIntroduction;
institutionInfo.value.name = res.data.orgName institutionInfo.value.name = res.data.orgName;
} }
} catch (error) {}
} catch (error) { };
}
}
handleGetInfo() handleGetInfo();
const activeTabName = ref("机构详情"); const activeTabName = ref("机构详情");
const tabList = ref([ const tabList = ref([
{ {
name: "机构详情", name: "机构详情"
active: true
}, },
{ {
name: "深度挖掘", name: "深度挖掘"
active: false
}, },
{ {
name: "对话制裁", name: "对华制裁"
active: false
} }
]); ]);
const handleClickTab = (val, index) => { const handleClickTab = val => {
tabList.value.forEach(item => {
item.active = false;
});
tabList.value[index].active = true;
activeTabName.value = val.name; activeTabName.value = val.name;
window.sessionStorage.setItem("institutionActiveTabName", val.name);
}; };
onMounted(() => {
if (window.sessionStorage.getItem("institutionActiveTabName")) {
activeTabName.value = window.sessionStorage.getItem("institutionActiveTabName");
}
});
onUnmounted(() => {
window.sessionStorage.removeItem('institutionActiveTabName')
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -114,7 +116,7 @@ const handleClickTab = (val, index) => { ...@@ -114,7 +116,7 @@ const handleClickTab = (val, index) => {
background-image: url("./assets/images/bg.png"); background-image: url("./assets/images/bg.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 100% auto; background-size: 100% auto;
padding-top: 16px; padding-top: 16px;
.header { .header {
width: 1600px; width: 1600px;
height: 200px; height: 200px;
......
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
<div class="user-content"> <div class="user-content">
<div class="user-item" v-for="(item, index) in keyUser" :key="index"> <div class="user-item" v-for="(item, index) in keyUser" :key="index">
<div class="user-item-left"> <div class="user-item-left">
<img :src="item.avatarUrl" alt="" /> <img :src="item.avatarUrl?item.avatarUrl:DefaultIcon1" alt="" />
</div> </div>
<div class="user-item-right"> <div class="user-item-right">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.name }}</div>
...@@ -136,11 +136,13 @@ import User1 from "./assets/images/user1.png"; ...@@ -136,11 +136,13 @@ import User1 from "./assets/images/user1.png";
import User2 from "./assets/images/user2.png"; import User2 from "./assets/images/user2.png";
import User3 from "./assets/images/user3.png"; import User3 from "./assets/images/user3.png";
import User4 from "./assets/images/user4.png"; import User4 from "./assets/images/user4.png";
import DefaultIcon1 from "@/assets/icons/default-icon1.png";
import DefaultIcon2 from "@/assets/icons/default-icon2.png"; import DefaultIcon2 from "@/assets/icons/default-icon2.png";
import { getGovOrgLatestDynamics, getGovOrgKeyPerson } from "@/api/institution/index"; import { getGovOrgBasicInfo, getGovOrgLatestDynamics, getGovOrgKeyPerson } from "@/api/institution/index";
const route = useRoute() const route = useRoute()
// 基本信息
const basicInfo = ref({ const basicInfo = ref({
image: Img, image: Img,
shijian: "1948年", shijian: "1948年",
...@@ -149,6 +151,28 @@ const basicInfo = ref({ ...@@ -149,6 +151,28 @@ const basicInfo = ref({
xiashujigou: "工业与安全局、国际贸易管理局、专利商标局等", xiashujigou: "工业与安全局、国际贸易管理局、专利商标局等",
zhicaishouduan: "实体清单、军事最终用户清单、​​“301条款”关税、​​“232条款”关税、特别指定国民清单" zhicaishouduan: "实体清单、军事最终用户清单、​​“301条款”关税、​​“232条款”关税、特别指定国民清单"
}); });
const handleGetBasicInfo = async () => {
const params = {
id: route.query.id
}
try {
const res = await getGovOrgBasicInfo(params)
console.log('基本信息', res);
if(res.code === 200 && res.data) {
basicInfo.value.image = res.data.logoUrl
basicInfo.value.shijian = res.data.establishmentDate
basicInfo.value.dizhi = res.data.address
basicInfo.value.zhize = res.data.orgIntroduction
basicInfo.value.xiashujigou = res.data.branchOrglist.toString()
basicInfo.value.zhicaishouduan = res.data.taglist.toString()
}
} catch (error) {
}
}
// 关键人物 // 关键人物
const keyUser = ref([ const keyUser = ref([
...@@ -162,16 +186,6 @@ const keyUser = ref([ ...@@ -162,16 +186,6 @@ const keyUser = ref([
// avatarUrl: User2, // avatarUrl: User2,
// position: "副部长" // position: "副部长"
// }, // },
// {
// name: "杰弗里·凯斯勒",
// avatarUrl: User3,
// position: "工业与安全局局长"
// },
// {
// name: "约翰·斯奎尔斯",
// avatarUrl: User4,
// position: "专利商标局局长"
// }
]); ]);
const handleGetKeyUser = async () => { const handleGetKeyUser = async () => {
const params = { const params = {
...@@ -251,49 +265,7 @@ handleGetKeyUser(); ...@@ -251,49 +265,7 @@ handleGetKeyUser();
// }, // },
// tagList: ["集成电路"] // tagList: ["集成电路"]
// }, // },
// {
// title: "美国商务部:加强对华AI芯片出口限制",
// time: "2025 9月10日",
// content:
// "美国政府要求英特尔、AMD、英伟达等公司对向中国出口的先进AI处理器实施严格的许可证制度。英特尔Gaudi系列芯片等因性能超标明确受限。同时,考虑对中国AI初创企业DeepSeek实施制裁。",
// type: {
// name: "行政令",
// status: 2
// },
// tagList: ["人工智能", "集成电路"]
// },
// {
// title: "美国商务部:BIS更新“实体清单”",
// time: "2025 9月15日",
// content:
// "美国商务部工业和安全局宣布更新《出口管理条例》(EAR),并发布两项最终规则,将25家中国企业及其相关实体列入实体清单。",
// type: {
// name: "实体清单",
// status: 4
// },
// tagList: ["集成电路"]
// },
// {
// title: "美国商务部:​发布针对中国网联汽车的禁令",
// time: "2025 8月25日",
// content: "美国商务部工业与安全局(BIS)发布一项最终规则,禁止涉及销售或进口其认定软件与中国有关联的联网汽车的交易。",
// type: {
// name: "行政令",
// status: 2
// },
// tagList: ["能源", "先进制造"]
// },
// {
// title: "美国商务部:考虑对中国无人机实施新限制",
// time: "2025 8月19日",
// content:
// "美国商务部表示正在考虑制定新规则,以限制或禁止中国无人机在美国境内使用,并就所谓“保护无人机供应链”的潜在规则征求公众意见。",
// type: {
// name: "行政令",
// status: 2
// },
// tagList: ["先进制造"]
// }
// ]); // ]);
const dynamicsName = ref("机构动态"); const dynamicsName = ref("机构动态");
const isCrelated = ref(false); const isCrelated = ref(false);
...@@ -318,6 +290,7 @@ const handleGetLatestDynamics = async () => { ...@@ -318,6 +290,7 @@ const handleGetLatestDynamics = async () => {
const params = { const params = {
orgId: route.query.id, orgId: route.query.id,
cRelated: isCrelated.value ? "Y" : "N", cRelated: isCrelated.value ? "Y" : "N",
dynamicsType: dynamicsName === '机构动态' ? "org" : "person",
currentPage: 1, currentPage: 1,
pageSize: 9999999 pageSize: 9999999
}; };
...@@ -330,7 +303,13 @@ const handleGetLatestDynamics = async () => { ...@@ -330,7 +303,13 @@ const handleGetLatestDynamics = async () => {
} }
} catch (error) {} } catch (error) {}
}; };
onMounted(() => {
handleGetLatestDynamics(); handleGetLatestDynamics();
handleGetBasicInfo()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
...@@ -18,17 +18,17 @@ ...@@ -18,17 +18,17 @@
<div class="item"> <div class="item">
<div class="item-top">{{ "今年新增" }}</div> <div class="item-top">{{ "今年新增" }}</div>
<div class="item-bottom"> <div class="item-bottom">
<div class="item-bottom-left">{{ "95家" }}</div> <div class="item-bottom-left">{{ `${box1Info.currentYear.num}家` }}</div>
<div class="item-bottom-center">{{ "/" }}</div> <div class="item-bottom-center">{{ "/" }}</div>
<div class="item-bottom-right">{{ "1129家" }}</div> <div class="item-bottom-right">{{ `${box1Info.currentYear.totalNum}家` }}</div>
</div> </div>
</div> </div>
<div class="item"> <div class="item">
<div class="item-top">{{ "今年新增" }}</div> <div class="item-top">{{ "全部企业" }}</div>
<div class="item-bottom"> <div class="item-bottom">
<div class="item-bottom-left">{{ "95家" }}</div> <div class="item-bottom-left">{{ `${box1Info.allYear.num}家` }}</div>
<div class="item-bottom-center">{{ "/" }}</div> <div class="item-bottom-center">{{ "/" }}</div>
<div class="item-bottom-right">{{ "1129家" }}</div> <div class="item-bottom-right">{{ `${box1Info.allYear.totalNum}家` }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -80,17 +80,17 @@ ...@@ -80,17 +80,17 @@
<div class="item"> <div class="item">
<div class="item-top">{{ "今年新增" }}</div> <div class="item-top">{{ "今年新增" }}</div>
<div class="item-bottom"> <div class="item-bottom">
<div class="item-bottom-left">{{ "2次" }}</div> <div class="item-bottom-left">{{ `${box3Info.currentYear.num}次` }}</div>
<div class="item-bottom-center">{{ "/" }}</div> <div class="item-bottom-center">{{ "/" }}</div>
<div class="item-bottom-right">{{ "6次" }}</div> <div class="item-bottom-right">{{ `${box3Info.currentYear.totalNum}次` }}</div>
</div> </div>
</div> </div>
<div class="item"> <div class="item">
<div class="item-top">{{ "今年新增" }}</div> <div class="item-top">{{ "全部调查" }}</div>
<div class="item-bottom"> <div class="item-bottom">
<div class="item-bottom-left">{{ "16次" }}</div> <div class="item-bottom-left">{{ `${box3Info.allYear.num}次` }}</div>
<div class="item-bottom-center">{{ "/" }}</div> <div class="item-bottom-center">{{ "/" }}</div>
<div class="item-bottom-right">{{ "91次" }}</div> <div class="item-bottom-right">{{ `${box3Info.allYear.totalNum}次` }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -130,117 +130,245 @@ import { ref, computed, onMounted } from "vue"; ...@@ -130,117 +130,245 @@ import { ref, computed, onMounted } from "vue";
import setChart from "@/utils/setChart"; import setChart from "@/utils/setChart";
import getPieChart from "./utils/piechart"; import getPieChart from "./utils/piechart";
import getMultiLineChart from "./utils/multiLineChart"; import getMultiLineChart from "./utils/multiLineChart";
import { useRoute } from "vue-router";
import {
getGrowthNum,
getGrowthTrend,
getEntityListField,
getGrowth232Num,
getGrowth232Trend,
getSection232Field
} from "@/api/institution/index";
const route = useRoute();
const box1Info = ref({
currentYear: {
num: 0,
totalNum: 0
},
allYear: {
num: 0,
totalNum: 0
}
});
const handleGetGrowthNum = async () => {
const params = {
orgId: route.query.id
// orgId: 54
};
try {
const res = await getGrowthNum(params);
console.log("实体清单增长数量", res);
if (res.code === 200 && res.data) {
box1Info.value.currentYear.num = res.data.filter(item => {
return item.yearType === "currentYear";
})[0].chinaNum;
box1Info.value.currentYear.totalNum = res.data.filter(item => {
return item.yearType === "currentYear";
})[0].allNum;
box1Info.value.allYear.num = res.data.filter(item => {
return item.yearType === "AllYear";
})[0].chinaNum;
box1Info.value.allYear.totalNum = res.data.filter(item => {
return item.yearType === "AllYear";
})[0].allNum;
} else {
console.error(res);
}
} catch (error) {
console.error("获取实体清单数量error", error);
}
};
handleGetGrowthNum();
const box1Data = ref({ const box1Data = ref({
title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"], title: [],
data: [ data: [
{ {
name: "全部实体", name: "全部实体",
data: [1104, 468, 602, 635, 486, 622, 811, 967, 952, 1104, 1358, 1196] data: []
}, },
{ {
name: "中国实体", name: "中国实体",
data: [234, 263, 251, 224, 264, 255, 258, 234, 246, 249, 257, 268] data: []
} }
] ]
}); });
const handleGetBox1Data = async () => {
const params = {
orgId: route.query.id
// orgId: 54
};
try {
const res = await getGrowthTrend(params);
console.log("实体清单新增数量变数趋势", res);
if (res.code === 200 && res.data) {
box1Data.value.title = res.data.map(item => {
return item.year;
});
box1Data.value.data[0].data = res.data.map(item => {
return item.allNum;
});
box1Data.value.data[1].data = res.data.map(item => {
return item.chinaNum;
});
}
} catch (error) {}
};
const handleBox1 = async () => {
await handleGetBox1Data();
const box1Chart = getMultiLineChart(box1Data.value.title, box1Data.value.data[0].data, box1Data.value.data[1].data);
setChart(box1Chart, "box1Chart");
};
const box2Data = ref([ const box2Data = ref([
{ // {
name: "集成电路", // name: "集成电路",
value: 50 // value: 50
}, // },
{ ]);
name: "人工智能", const handleGetBox2Data = async () => {
value: 46 const params = {
}, orgId: route.query.id,
{ // orgId: 54,
name: "通信网络", year: 2025
value: 40 };
}, try {
{ const res = await getEntityListField(params);
name: "能源", console.log("实体清单新增企业领域分布", res);
value: 32 if (res.code === 200 && res.data) {
}, box2Data.value = res.data.map(item => {
{ return {
name: "先进制造", name: item.industry,
value: 31 value: item.amount
}, };
{ });
name: "生物科技", }
value: 31 } catch (error) {}
}, };
{
name: "航空航天", const handleBox2 = async () => {
value: 30 await handleGetBox2Data();
const box2Chart = getPieChart(box2Data.value);
setChart(box2Chart, "box2Chart");
};
const box3Info = ref({
currentYear: {
num: 0,
totalNum: 0
}, },
{ allYear: {
name: "新材料", num: 0,
value: 24 totalNum: 0
} }
]); });
const handleGetGrowth232Num = async () => {
const params = {
orgId: route.query.id
// orgId: 54
};
try {
const res = await getGrowth232Num(params);
console.log("232调查新增数量", res);
if (res.code === 200 && res.data) {
box3Info.value.currentYear.num = res.data.filter(item => {
return item.yearType === "currentYear";
})[0].chinaNum;
box3Info.value.currentYear.totalNum = res.data.filter(item => {
return item.yearType === "currentYear";
})[0].allNum;
box3Info.value.allYear.num = res.data.filter(item => {
return item.yearType === "AllYear";
})[0].chinaNum;
box3Info.value.allYear.totalNum = res.data.filter(item => {
return item.yearType === "AllYear";
})[0].allNum;
} else {
console.error(res);
}
} catch (error) {
console.error("获取232调查新增数量error", error);
}
};
handleGetGrowth232Num();
const box3Data = ref({ const box3Data = ref({
title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"], title: [],
data: [ data: [
{ {
name: "全部调查", name: "全部调查",
data: [856, 456, 568, 631, 667, 631, 532, 589, 631, 668, 672, 630] data: []
}, },
{ {
name: "涉华调查", name: "涉华调查",
data: [188, 195, 198, 205, 208, 214, 218, 223, 216, 219, 211, 204] data: []
} }
] ]
}); });
const box4Data = ref([ const handleGetBox3Data = async () => {
{ const params = {
name: "集成电路", orgId: route.query.id
value: 50 // orgId: 54
}, };
{ try {
name: "人工智能", const res = await getGrowth232Trend(params);
value: 46 console.log("232调查新增数量变数趋势", res);
}, if (res.code === 200 && res.data) {
{ box3Data.value.title = res.data.map(item => {
name: "通信网络", return item.year;
value: 40 });
}, box3Data.value.data[0].data = res.data.map(item => {
{ return item.allNum;
name: "能源", });
value: 32 box3Data.value.data[1].data = res.data.map(item => {
}, return item.chinaNum;
{ });
name: "先进制造", }
value: 31 } catch (error) {}
}, };
{ const handleBox3 = async () => {
name: "生物科技", await handleGetBox3Data();
value: 31
},
{
name: "航空航天",
value: 30
},
{
name: "新材料",
value: 24
}
]);
onMounted(() => {
const box1Chart = getMultiLineChart(box1Data.value.title, box1Data.value.data[0].data, box1Data.value.data[1].data);
setChart(box1Chart, "box1Chart");
const box2Chart = getPieChart(box2Data.value);
setChart(box2Chart, "box2Chart");
const box3Chart = getMultiLineChart(box3Data.value.title, box3Data.value.data[0].data, box3Data.value.data[1].data); const box3Chart = getMultiLineChart(box3Data.value.title, box3Data.value.data[0].data, box3Data.value.data[1].data);
setChart(box3Chart, "box3Chart"); setChart(box3Chart, "box3Chart");
};
const box4Data = ref([]);
const handleGetBox4Data = async () => {
const params = {
orgId: route.query.id,
// orgId: 54,
startDate: "2021-01-01"
};
try {
const res = await getSection232Field(params);
console.log("232调查新增企业领域分布", res);
if (res.code === 200 && res.data) {
box4Data.value = res.data.map(item => {
return {
name: item.industry,
value: item.amount
};
});
}
} catch (error) {}
};
const handleBox4 = async () => {
await handleGetBox4Data();
const box4Chart = getPieChart(box4Data.value); const box4Chart = getPieChart(box4Data.value);
setChart(box4Chart, "box4Chart"); setChart(box4Chart, "box4Chart");
};
onMounted(() => {
handleBox1();
handleBox2();
handleBox3();
handleBox4();
}); });
</script> </script>
......
...@@ -69,39 +69,39 @@ ...@@ -69,39 +69,39 @@
</div> </div>
</div> </div>
<div class="home-main-header-card-box"> <div class="home-main-header-card-box">
<div class="home-main-header-card-box-box1 card" @click="handleClickToDetail('301')"> <div class="home-main-header-card-box-box1 card" @click="handleClickToDetail(sortInfo[1]?.sortCode)">
<div class="header"> <div class="header">
<div class="header-left">{{ "301调查" }}</div> <div class="header-left">{{ sortInfo[1]?.sortName }}</div>
<div class="header-right">{{ "52项" }}</div> <div class="header-right">{{ `${sortInfo[1]?.sortCount}项` }}</div>
</div> </div>
<div class="content-box"> <div class="content-box">
<div class="item">{{ "可能措施: 加征关税、限制进口" }}</div> <div class="item">{{ sortInfo[1]?.sortMeasure }}</div>
<div class="item"> <div class="item">
{{ '依据《1974年贸易法》第301条针对"不合理或不公正贸易做法"' }} {{ sortInfo[1]?.sortDescription }}
</div> </div>
</div> </div>
</div> </div>
<div class="home-main-header-card-box-box2 card" @click="handleClickToDetail('232')"> <div class="home-main-header-card-box-box2 card" @click="handleClickToDetail(sortInfo[2]?.sortCode)">
<div class="header"> <div class="header">
<div class="header-left">{{ "232调查" }}</div> <div class="header-left">{{ sortInfo[2]?.sortName }}</div>
<div class="header-right">{{ "3项" }}</div> <div class="header-right">{{ `${sortInfo[2]?.sortCount}项` }}</div>
</div> </div>
<div class="content-box"> <div class="content-box">
<div class="item">{{ "可能措施: 加征关税、限制进口" }}</div> <div class="item">{{ sortInfo[2]?.sortMeasure }}</div>
<div class="item"> <div class="item">
{{ "依据《1962年贸易扩展法》第232条评估进口产品对国家安全影响" }} {{ sortInfo[2]?.sortDescription }}
</div> </div>
</div> </div>
</div> </div>
<div class="home-main-header-card-box-box3 card" @click="handleClickToDetail('337')"> <div class="home-main-header-card-box-box3 card" @click="handleClickToDetail(sortInfo[0]?.sortCode)">
<div class="header"> <div class="header">
<div class="header-left">{{ "337调查" }}</div> <div class="header-left">{{ sortInfo[0]?.sortName }}</div>
<div class="header-right">{{ "87项" }}</div> <div class="header-right">{{ `${sortInfo[0]?.sortCount}项` }}</div>
</div> </div>
<div class="content-box"> <div class="content-box">
<div class="item">{{ "可能措施: 排除令、禁止令" }}</div> <div class="item">{{ sortInfo[0]?.sortMeasure }}</div>
<div class="item"> <div class="item">
{{ "依据《1930年关税法》第337条针对知识产权侵权行为" }} {{ sortInfo[0]?.sortDescription }}
</div> </div>
</div> </div>
</div> </div>
...@@ -111,10 +111,10 @@ ...@@ -111,10 +111,10 @@
<DivideHeader id="position1" class="divide-header" :titleText="'最新动态'"></DivideHeader> <DivideHeader id="position1" class="divide-header" :titleText="'最新动态'"></DivideHeader>
<div class="center-top"> <div class="center-top">
<div class="box1"> <div class="box1">
<div class="box1-left"> <div class="box1-left" @click="handleSwithCurSurvey('left')">
<img src="./assets/images/box1-left.png" alt="" /> <img src="./assets/images/box1-left.png" alt="" />
</div> </div>
<div class="box1-right"> <div class="box1-right" @click="handleSwithCurSurvey('right')">
<img src="./assets/images/box1-right.png" alt="" /> <img src="./assets/images/box1-right.png" alt="" />
</div> </div>
<div class="box1-header"> <div class="box1-header">
...@@ -128,68 +128,73 @@ ...@@ -128,68 +128,73 @@
{{ "查看详情 >" }} {{ "查看详情 >" }}
</div> </div>
</div> </div>
<div class="box1-main"> <el-carousel
<div class="box1-main-header"> ref="carouselRef"
<div class="header-left"> height="395px"
{{ "美国ITC发布对外国制造的半导体器件及其下游产品和组件的337部分终裁" }} :autoplay="true"
</div> :interval="3000"
<div class="header-right"> arrow="never"
<div class="tag1">{{ "337" }}</div> indicator-position="none"
<div class="tag2">{{ "半导体" }}</div> >
</div> <el-carousel-item v-for="(item, index) in box1DataList" :key="index">
</div> <div class="box1-main">
<div class="info-box"> <div class="box1-main-header">
<div class="info-header"> <div class="header-left">
<div class="icon"></div> {{ item.SEARCHNAME }}
<div class="time">{{ "2025-08-15" }}</div> </div>
<div class="title">{{ "部分终裁" }}</div> <div class="header-right">
</div> <div class="tag1">{{ item.SEARCHSORT }}</div>
<div class="info-content"> <div class="tag2" v-for="(val, idx) in item.searchArea" :key="idx">{{ val }}</div>
{{ </div>
"对本案行政法官于2025年7月31日作出的初裁(No.36)不予复审,即基于申请方撤回,终止本案对美国注册专利号9,093,473第4项申诉的调查。"
}}
</div>
</div>
<div class="list-box">
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "调查案号:" }}</div>
<div class="list-right">{{ "337-TA-1443" }}</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "涉及产品:" }}</div>
<div class="list-right">
{{
"对美出口、在美进口及销售的特定外国制造的半导体器件及其下游产品和组件(Certain Foreign-Fabricated ..."
}}
</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "原告:" }}</div>
<div class="list-right">
{{ "爱尔兰Longitude Licensing Ltd.、爱尔兰Marlin Semiconductor Limited" }}
</div> </div>
</div> <div class="info-box">
<div class="list-item"> <div class="info-header">
<div class="icon"></div> <div class="icon"></div>
<div class="list-left">{{ "被告:" }}</div> <div class="time">{{ item.PROGRESSDATE }}</div>
<div class="list-right"> <div class="title">{{ item.PROGRESSRESULT }}</div>
{{ </div>
"中国台湾地区Taiwan Semiconductor Manufacturing Company Limited of Taiwan、美国Apple Inc. of ...." <div class="info-content">
}} {{ item.PROGRESSDETAILS }}
</div>
</div> </div>
</div> <div class="list-box">
<div class="list-item"> <div class="list-item">
<div class="icon"></div> <div class="icon"></div>
<div class="list-left">{{ "涉案专利" }}</div> <div class="list-left">{{ "调查案号:" }}</div>
<div class="list-right"> <div class="list-right">{{ item.SEARCHNUM }}</div>
{{ "美国注册专利号7745847、9093473、9147747、9184292" }} </div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "涉及产品:" }}</div>
<div class="list-right">
{{ item.PRODUCT }}
</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "原告:" }}</div>
<div class="list-right">
{{ item.PLAINTIFF }}
</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "被告:" }}</div>
<div class="list-right">
{{ item.DEFENDANT }}
</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "涉案专利" }}</div>
<div class="list-right">
{{ item.PATENT }}
</div>
</div>
</div> </div>
</div> </div>
</div> </el-carousel-item>
</div> </el-carousel>
</div> </div>
<div class="box2"> <div class="box2">
<div class="box2-header"> <div class="box2-header">
...@@ -198,25 +203,39 @@ ...@@ -198,25 +203,39 @@
</div> </div>
<div class="title"> <div class="title">
<div class="text">{{ "风险信号" }}</div> <div class="text">{{ "风险信号" }}</div>
<div class="num">{{ warningList.length }}</div> <div class="num">{{ box2Data.length }}</div>
</div> </div>
</div> </div>
<div class="box2-main"> <div class="box2-main">
<div class="box2-main-item" v-for="(item, index) in warningList" :key="index"> <div class="box2-main-item" v-for="(item, index) in box2Data" :key="index">
<div <div
class="item-left" class="item-left"
:class="{ :class="{
itemLeftStatus1: item.status === '一般风险', itemLeftStatus3: item.signalLevel === '特别重大',
itemLeftStatus2: item.status === '重大风险' itemLeftStatus2: item.signalLevel === '重大风险'
}" }"
> >
{{ item.status }} {{ item.signalLevel }}
</div> </div>
<div class="item-right"> <div class="item-right">
<div class="text"> <el-popover
{{ item.title }} v-if="item.signalTitle?.length > 20"
effect="dark"
:width="480"
:content="item.signalTitle"
placement="top"
>
<template #reference>
<div class="text">
{{ item.signalTitle }}
</div>
</template>
</el-popover>
<div v-else class="text">
{{ item.signalTitle }}
</div> </div>
<div class="time">{{ item.time }}</div>
<div class="time">{{ item.signalTime }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -241,16 +260,25 @@ ...@@ -241,16 +260,25 @@
</div> </div>
</div> </div>
<div class="box3-main"> <div class="box3-main">
<div class="box3-item" v-for="(news, index) in newsList" :key="index"> <div
class="box3-item"
v-for="(news, index) in newsList"
:key="index"
@click="handleToNewsAnalysis(news)"
>
<div class="left"> <div class="left">
<img :src="news.img" alt="" /> <img :src="news.newsImage ? news.newsImage : DefaultNewsIcon" alt="" />
</div> </div>
<div class="right"> <div class="right">
<div class="right-top"> <div class="right-top">
<div class="title">{{ news.title }}</div> <div class="title">{{ news.newsTitle }}</div>
<div class="time">{{ news.from }}</div> <div class="time">{{ news.newsDate + " · " + news.newsOrg }}</div>
</div> </div>
<div class="right-footer">{{ news.content }}</div> <el-popover effect="dark" :width="1000" :content="news.newsContent" placement="top-start">
<template #reference>
<div class="right-footer">{{ news.newsContent }}</div>
</template>
</el-popover>
</div> </div>
</div> </div>
</div> </div>
...@@ -264,15 +292,15 @@ ...@@ -264,15 +292,15 @@
</div> </div>
<div class="box4-main"> <div class="box4-main">
<div class="box4-main-item" v-for="(item, index) in messageList" :key="index"> <div class="box4-main-item" v-for="(item, index) in messageList" :key="index">
<div class="left"> <div class="left" @click="handleClickPerson()">
<img :src="item.img" alt="" /> <img :src="item.personImage ? item.personImage : DefaultUserIcon" alt="" />
</div> </div>
<div class="right"> <div class="right">
<div class="right-top"> <div class="right-top">
<div class="name">{{ item.name }}</div> <div class="name">{{ item.personName }}</div>
<div class="time">{{ item.time }}</div> <div class="time">{{ item.time + " · " + item.orgName }}</div>
</div> </div>
<div class="content">{{ item.content }}</div> <div class="content">{{ item.remarks }}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -298,11 +326,14 @@ ...@@ -298,11 +326,14 @@
<div class="box5-main"> <div class="box5-main">
<div class="box5-main-chart" id="chart1"></div> <div class="box5-main-chart" id="chart1"></div>
<div class="box5-main-btn-box"> <div class="box5-main-btn-box">
<div class="right-box rightBoxActive"> <div
{{ "按月度" }} class="right-box"
</div> :class="{ rightBoxActive: box5BtnActive === item.value }"
<div class="right-box"> v-for="(item, index) in box5BtnList"
{{ "按年度" }} :key="index"
@click="handleChangeBox5Btn(item.value)"
>
{{ item.name }}
</div> </div>
</div> </div>
</div> </div>
...@@ -322,7 +353,12 @@ ...@@ -322,7 +353,12 @@
</div> </div>
<div class="box6-main"> <div class="box6-main">
<div class="box6-main-select-box"> <div class="box6-main-select-box">
<el-select v-model="box6SelectedYear" placeholder="选择时间" style="width: 120px"> <el-select
v-model="box6SelectedYear"
@change="handleChangeBox6Year"
placeholder="选择时间"
style="width: 120px"
>
<el-option <el-option
v-for="item in box6YearList" v-for="item in box6YearList"
:key="item.value" :key="item.value"
...@@ -355,7 +391,12 @@ ...@@ -355,7 +391,12 @@
<div class="box7-main-left" id="box7Chart1"></div> <div class="box7-main-left" id="box7Chart1"></div>
<div class="box7-main-right"> <div class="box7-main-right">
<div class="box7-main-right-top"> <div class="box7-main-right-top">
<el-select v-model="box7SelectedYear" placeholder="选择时间" style="width: 120px"> <el-select
v-model="box7SelectedYear"
@change="handleChangeBox7Year"
placeholder="选择时间"
style="width: 120px"
>
<el-option <el-option
v-for="item in box7YearList" v-for="item in box7YearList"
:key="item.value" :key="item.value"
...@@ -406,7 +447,7 @@ ...@@ -406,7 +447,7 @@
<div class="box8-main-item" v-for="(item, index) in box8Data" :key="index"> <div class="box8-main-item" v-for="(item, index) in box8Data" :key="index">
<div class="item-1"> <div class="item-1">
<div class="icon"> <div class="icon">
<img :src="item.logo" alt="" /> <img :src="item.logo ? item.logo : DefaultCompanyIcon" alt="" />
</div> </div>
<div class="text"> <div class="text">
{{ item.name }} {{ item.name }}
...@@ -428,35 +469,34 @@ ...@@ -428,35 +469,34 @@
<div class="btn-box"> <div class="btn-box">
<div <div
class="btn" class="btn"
:class="{ btnActive: activeCate === cate }" :class="{ btnActive: activeCateId === cate.id }"
v-for="(cate, index) in categoryList" v-for="(cate, index) in categoryList"
:key="index" :key="index"
@click="handleClickCate(cate)" @click="handleClickCate(cate)"
> >
{{ cate }} {{ cate.name }}
</div> </div>
</div> </div>
<div class="select-box"> <div class="select-box">
<el-select v-model="releaseTime" placeholder="选择发布时间" style="width: 120px"> <div class="paixu-btn" @click="handleSwithSort">
<div class="icon1">
<img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" />
<img v-else src="@/assets/icons/jiangxu1.png" alt="" />
</div>
<div class="text">{{ "发布时间" }}</div>
<div class="icon2">
<img v-if="isSort" src="@/assets/icons/shengxu2.png" alt="" />
<img v-else src="@/assets/icons/jiangxu2.png" alt="" />
</div>
</div>
<!-- <el-select v-model="releaseTime" placeholder="选择发布时间" style="width: 120px">
<el-option <el-option
v-for="item in releaseTimeList" v-for="item in releaseTimeList"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select> -->
<!-- <el-select
v-model="releaseTime"
placeholder="选择发布时间"
style="width: 120px"
>
<el-option
v-for="item in releaseTimeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select> -->
</div> </div>
</div> </div>
<div class="home-main-footer-main"> <div class="home-main-footer-main">
...@@ -467,8 +507,18 @@ ...@@ -467,8 +507,18 @@
<div class="title">{{ "发布时间" }}</div> <div class="title">{{ "发布时间" }}</div>
</div> </div>
<div class="left-box1-main"> <div class="left-box1-main">
<div class="time-label" v-for="(item, index) in surveyYearList" :key="index"> <div class="checkbox-group">
<el-checkbox v-model="item.selected" :label="item.name" size="large" /> <el-checkbox
v-for="year in surveyYearList"
:key="year.id"
v-model="checkedSurveyYears"
:label="year.id"
style="width: 180px"
class="filter-checkbox"
@change="handleChangeCheckedSurveyYears"
>
{{ year.name }}
</el-checkbox>
</div> </div>
</div> </div>
</div> </div>
...@@ -478,8 +528,18 @@ ...@@ -478,8 +528,18 @@
<div class="title">{{ "涉及领域" }}</div> <div class="title">{{ "涉及领域" }}</div>
</div> </div>
<div class="left-box2-main"> <div class="left-box2-main">
<div class="area-label" v-for="(item, index) in surveyAreaList" :key="index"> <div class="checkbox-group">
<el-checkbox v-model="item.selected" :label="item.name" size="large" /> <el-checkbox
v-for="area in areaList"
:key="area.id"
v-model="checkedAreaList"
:label="area.id"
style="width: 110px"
class="filter-checkbox"
@change="handleChangeCheckedAreas"
>
{{ area.name }}
</el-checkbox>
</div> </div>
</div> </div>
</div> </div>
...@@ -493,32 +553,39 @@ ...@@ -493,32 +553,39 @@
<div class="header-item5">{{ "发布日期" }}</div> <div class="header-item5">{{ "发布日期" }}</div>
</div> </div>
<div class="right-main"> <div class="right-main">
<div class="item" v-for="(val, idx) in surveyInfoList" :key="idx"> <div class="item" v-for="(val, idx) in surveyInfoList" :key="idx" @click="handleClickToSurveyDetail(val.SORTCODE)">
<div class="item-box1"> <div class="item-box1">
<div <div
class="name" class="name"
:class="{ :class="{
name1: val.name === '301', name1: val.SORTCODE === '301',
name2: val.name === '337', name2: val.SORTCODE === '337',
name3: val.name === '232' name3: val.SORTCODE === '232'
}" }"
> >
{{ val.name }} {{ val.SORTCODE }}
</div> </div>
<div class="title">{{ val.title }}</div> <div class="title">{{ val.SEARCHNAME }}</div>
</div> </div>
<div class="item-box2">{{ val.num }}</div> <div class="item-box2">{{ val.SEARCHID }}</div>
<div class="item-box3">{{ val.area }}</div> <div class="item-box3">{{ val.searchArea?.toString() }}</div>
<div class="item-box4">{{ val.status }}</div> <div class="item-box4">{{ val.CASESTATUS }}</div>
<div class="item-box5">{{ val.releaseDate }}</div> <div class="item-box5">{{ val.SEARCHDATEZH }}</div>
</div> </div>
</div> </div>
<div class="right-footer"> <div class="right-footer">
<div class="footer-left"> <div class="footer-left">
{{ "共105项调查" }} {{ `共${totalDiscussNum}项调查` }}
</div> </div>
<div class="footer-right"> <div class="footer-right">
<el-pagination background layout="prev, pager, next" :total="105" /> <el-pagination
@current-change="handleCurrentChange"
:pageSize="pageSize"
:current-page="currentPage"
background
layout="prev, pager, next"
:total="totalDiscussNum"
/>
</div> </div>
</div> </div>
</div> </div>
...@@ -530,8 +597,8 @@ ...@@ -530,8 +597,8 @@
<script setup> <script setup>
import { onMounted, ref } from "vue"; import { onMounted, ref } from "vue";
import setChart from "@/utils/setChart";
import scrollToTop from "@/utils/scrollToTop"; import scrollToTop from "@/utils/scrollToTop";
import * as echarts from "echarts";
import router from "@/router"; import router from "@/router";
import DivideHeader from "@/components/DivideHeader.vue"; import DivideHeader from "@/components/DivideHeader.vue";
...@@ -556,15 +623,57 @@ import Logo2 from "./assets/images/logo2.png"; ...@@ -556,15 +623,57 @@ import Logo2 from "./assets/images/logo2.png";
import Logo3 from "./assets/images/logo3.png"; import Logo3 from "./assets/images/logo3.png";
import Logo4 from "./assets/images/logo4.png"; import Logo4 from "./assets/images/logo4.png";
import Logo5 from "./assets/images/logo5.png"; import Logo5 from "./assets/images/logo5.png";
import {
getStatSort,
getStatNum,
getStatDetails,
getStatArea,
getHylyList,
getSurveyList,
getStatAreaCompanyList,
getCompanyPlace
} from "@/api/marketAccessRestrictions/index";
import { getRiskSignal, getNews, getRemarks } from "@/api/common/index";
import { ElMessage } from "element-plus";
// 返回首页 import DefaultUserIcon from "@/assets/icons/default-icon1.png";
const handleBackHome = () => { import DefaultCompanyIcon from "@/assets/icons/default-icon2.png";
router.push({ import DefaultNewsIcon from "@/assets/icons/default-icon-news.png";
path: "/overview"
}); // 首页分类
const sortInfo = ref([{}]);
const handleGetStatSort = async () => {
try {
const res = await getStatSort();
console.log("首页分类", res);
sortInfo.value = res.data;
} catch (error) {}
};
// 调查进展
const box1DataList = ref([]);
const handleGetBox1Data = async () => {
try {
const res = await getStatDetails();
console.log("调查进展", res);
if (res.code === 200 && res.data) {
box1DataList.value = res.data;
}
} catch (error) {}
}; };
const handleClickToDetail = id => { const carouselRef = ref(null);
// 点击查看详情
const handleClickToDetail = () => {
let activeIndex = 0;
if (carouselRef.value) {
activeIndex = carouselRef.value.activeIndex;
}
console.log("当前 Carousel 激活索引:", activeIndex);
const id = box1DataList.value[activeIndex].SEARCHSORT;
const route = router.resolve({ const route = router.resolve({
path: "/marketAccessLayout", path: "/marketAccessLayout",
query: { query: {
...@@ -574,8 +683,17 @@ const handleClickToDetail = id => { ...@@ -574,8 +683,17 @@ const handleClickToDetail = id => {
window.open(route.href, "_blank"); window.open(route.href, "_blank");
}; };
// 切换当前调查
const handleSwithCurSurvey = name => {
if (name === "left") {
carouselRef.value.prev();
} else {
carouselRef.value.next();
}
};
// 风险信号 // 风险信号
const warningList = ref([ const box2Data = ref([
{ {
title: "关于对中华人民共和国合成阿片类药物供应链...", title: "关于对中华人民共和国合成阿片类药物供应链...",
time: "一天前", time: "一天前",
...@@ -585,70 +703,210 @@ const warningList = ref([ ...@@ -585,70 +703,210 @@ const warningList = ref([
title: "关于调整汽车及汽车零部件进口的公告", title: "关于调整汽车及汽车零部件进口的公告",
time: "一天前", time: "一天前",
status: "特别重大" status: "特别重大"
}
]);
const handleGetBox2Data = async () => {
const params = {
moduleId: "0104"
};
try {
const res = await getRiskSignal(params);
console.log("风险信号", res);
if (res.code === 200 && res.data) {
box2Data.value = res.data;
}
} catch (error) {}
};
// 新闻资讯
const newsList = ref([
{
img: News1,
title: "美政府停摆仍持续,拨款法案存缺陷,但两党磋商露曙光",
content: `美国政府停摆已持续34天,距离历史上最长的停摆纪录仅差一天,参议院已先后13次尝试...`,
from: "11-4 · 华盛顿邮报"
}, },
{ {
title: "关于调整钢铁进口的公告", img: News2,
time: "一天前", title: "美参议院通过决议,要求终止特朗普全球关税政策",
status: "重大风险" content: `参议院以51票赞成、47票反对通过一项决议,旨在终止特朗普实施的全面关税政策,四名......`,
from: "11-4 · 纽约时报"
}, },
{ {
title: "关于使用互惠关税规范进口以纠正导致大规模...", img: News3,
time: "一天前", title: "美众院通过950亿美元对外援助法案,包含对台军援",
status: "重大风险" content: `国会众议院在4月通过了大规模对外援助法案,其中包括为“印太安全”提供资金的条款,......`,
from: "11-3 · 洛杉矶时报"
}, },
{ {
title: "关于修订对中华人民共和国低价值进口商品适...", img: News4,
time: "一天前", title: "“大而美”法案在激烈争议中通过",
status: "一般风险" content: `特朗普力推的大规模税收与支出法案在国会以微弱优势通过。该法案因大幅削减医疗补助和......`,
from: "11-3 · 今日美国"
},
{
img: News5,
title: "美政府“停摆”追平历史最长纪录,民生多领域受重创",
content: `联邦政府“停摆”进入第35天,追平历史纪录。食品救济项目资金中断,数百万低收入民......`,
from: "11-2 · ​福克斯新闻网"
} }
]); ]);
// 获取新闻资讯列表
const handleGetBox3Data = async () => {
const params = {
moduleId: "0104"
};
try {
const res = await getNews(params);
console.log("新闻资讯", res);
if (res.code === 200 && res.data) {
newsList.value = res.data;
}
} catch (error) {}
};
// 点击新闻条目,跳转到新闻分析页
const handleToNewsAnalysis = news => {
const route = router.resolve({
path: "/newsAnalysis",
query: {
newsId: news.newsId
}
});
window.open(route.href, "_blank");
};
const releaseTime = ref("近一年发布"); // 社交媒体
const messageList = ref([]);
const releaseTimeList = ref([ const handleGetBox4Data = async () => {
{ const params = {
label: "近半年发布", moduleId: "0104"
value: "近半年发布" };
}, try {
{ const res = await getRemarks(params);
label: "近一年发布", console.log("社交媒体", res);
value: "近一年发布" if (res.code === 200 && res.data) {
}, messageList.value = res.data;
{ }
label: "近两年发布", } catch (error) {}
value: "近两年发布" };
}, // 点击人物头像,跳转到人物主页
const handleClickPerson = () => {
const route = router.resolve({
path: "/characterPage",
query: {
type: 3 // 1 2 3
}
});
window.open(route.href, "_blank");
};
// 调查数量
const box5BtnList = ref([
{ {
label: "近三年发布", name: "按月度",
value: "近三年发布" value: 1
}, },
{ {
label: "近五年发布", name: "按年度",
value: "近五年发布" value: 12
} }
]); ]);
const box5BtnActive = ref(1);
const handleChangeBox5Btn = val => {
box5BtnActive.value = val;
handleBox5();
};
function transformAllData(originalData) {
// 1. 提取所有年份并去重,排除null和undefined,然后按数字升序排序
const allYears = [
...new Set(
originalData.filter(item => item.searchYorM != null && item.searchYorM !== "").map(item => String(item.searchYorM))
)
].sort((a, b) => Number(a) - Number(b));
const categoryList = ref(["全部调查", "301调查", "232调查", "337调查"]); // 2. 获取所有调查类型并去重
const allCategories = [...new Set(originalData.map(item => item.sortName))];
const activeCate = ref("全部调查"); // 3. 为每个类别创建值数组
const activeHylyId = ref(""); const categoryData = allCategories.map(category => {
// 对于每个年份,查找对应的数据
const values = allYears.map(year => {
// 查找匹配当前类别和年份的数据
const matchingItem = originalData.find(item => item.sortName === category && String(item.searchYorM) === year);
const handleClickCate = cate => { // 如果找到则返回searchCount,否则返回0
console.log(cate); return matchingItem ? matchingItem.searchCount : 0;
});
activeCate.value = cate.hylymc; return {
activeHylyId.value = cate.hylyid; name: category,
handleGetBillsByType(); value: values
}; };
});
// 绘制echarts图表 // 4. 构建最终结果
const setChart = (option, chartId) => { return {
let chartDom = document.getElementById(chartId); title: allYears,
chartDom.removeAttribute("_echarts_instance_"); data: categoryData
let chart = echarts.init(chartDom); };
chart.setOption(option); }
return chart;
}; function transformAllData1(originalData) {
// 1. 提取所有年月并去重,排除null和undefined,然后按时间顺序排序
const allDates = [
...new Set(
originalData.filter(item => item.searchYorM != null && item.searchYorM !== "").map(item => String(item.searchYorM))
)
].sort((a, b) => {
// 自定义排序函数,处理年月格式
const parseDate = dateStr => {
if (dateStr.includes("-")) {
// 处理 "YYYY-MM" 格式
const [year, month] = dateStr.split("-").map(Number);
return { year, month: month || 0 };
} else {
// 处理纯年份格式
return { year: Number(dateStr), month: 0 };
}
};
const dateA = parseDate(a);
const dateB = parseDate(b);
// 先比较年份,再比较月份
if (dateA.year !== dateB.year) {
return dateA.year - dateB.year;
}
return dateA.month - dateB.month;
});
// 2. 获取所有调查类型并去重
const allCategories = [...new Set(originalData.map(item => item.sortName))];
// 3. 为每个类别创建值数组
const categoryData = allCategories.map(category => {
// 对于每个日期,查找对应的数据
const values = allDates.map(date => {
// 查找匹配当前类别和日期的数据
const matchingItem = originalData.find(item => item.sortName === category && String(item.searchYorM) === date);
// 如果找到则返回searchCount,否则返回0
return matchingItem ? matchingItem.searchCount : 0;
});
return {
name: category,
value: values
};
});
// 4. 构建最终结果
return {
title: allDates,
data: categoryData
};
}
const chart1Data = ref({ const chart1Data = ref({
title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"], title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
...@@ -667,8 +925,32 @@ const chart1Data = ref({ ...@@ -667,8 +925,32 @@ const chart1Data = ref({
} }
] ]
}); });
const hadleGetStatNum = async () => {
const params = {
byYorM: box5BtnActive.value // 月度:1 年度:12
};
try {
const res = await getStatNum(params);
console.log("调查数量", res);
if (res.code === 200 && res.data) {
if (box5BtnActive.value === 1) {
chart1Data.value = transformAllData1(res.data);
} else {
chart1Data.value = transformAllData(res.data);
}
}
} catch (error) {}
};
const box7YearList = ref([ const handleBox5 = async () => {
await hadleGetStatNum();
let chart1 = getMultiLineChart(chart1Data.value);
setChart(chart1, "chart1");
};
// 制裁领域分布
const box6SelectedYear = ref("2025");
const box6YearList = ref([
{ {
label: "2025", label: "2025",
value: "2025" value: "2025"
...@@ -694,216 +976,101 @@ const box7YearList = ref([ ...@@ -694,216 +976,101 @@ const box7YearList = ref([
value: "2020" value: "2020"
} }
]); ]);
const handleChangeBox6Year = () => {
handleBox6();
};
const box6Data = ref({
title: [],
data: [
{
name: "337调查",
value: []
},
{
name: "232调查",
value: []
},
{
name: "301调查",
value: []
}
],
maxNum: 0
});
const handleGetStatArea = async () => {
const params = {
years: box6SelectedYear.value
};
try {
const res = await getStatArea(params);
console.log("制裁领域分布", res);
if (res.code === 200 && res.data) {
const arr = res.data.map(item => {
return item.AREANAME;
});
box6Data.value.title = [...new Set(arr)];
const box7SelectedYear = ref("2025"); const arr1 = res.data.filter(item => {
return item.SORTNAME === "337调查";
const surveyYearList = ref([ });
{ const arr1Name = arr1.map(item => {
name: "全部时间", return item.AREANAME;
selected: false });
}, box6Data.value.title.forEach((item, index) => {
{ if (arr1Name.indexOf(item) > -1) {
name: "2025年", const idx = arr1Name.indexOf(item);
selected: false box6Data.value.data[0].value[index] = arr1[idx].AREACOUNT;
}, } else {
{ box6Data.value.data[0].value[index] = 0;
name: "2024年", }
selected: false });
},
{
name: "2023年",
selected: false
},
{
name: "2022年",
selected: false
},
{
name: "2021年",
selected: false
}
]);
const surveyAreaList = ref([
{
name: "人工智能",
selected: false
},
{
name: "半导体/芯片",
selected: false
},
{
name: "电子设备",
selected: false
},
{
name: "显示技术",
selected: false
},
{
name: "新能源",
selected: false
},
{
name: "通信设备",
selected: false
}
]);
const surveyInfoList = ref([ const arr2 = res.data.filter(item => {
{ return item.SORTNAME === "232调查";
name: "301", });
title: "某些车辆远程信息处理、车队管理以及基于视频的安全系统、设备和组件12", const arr2Name = arr2.map(item => {
num: "337-TA-1393", return item.AREANAME;
area: "半导体", });
status: "正在调查", box6Data.value.title.forEach((item, index) => {
releaseDate: "2025年9月1日" if (arr2Name.indexOf(item) > -1) {
}, const idx = arr2Name.indexOf(item);
{ box6Data.value.data[1].value[index] = arr2[idx].AREACOUNT;
name: "337", } else {
title: "某些蒸发器设备,其中使用的墨盒及其组件(II)", box6Data.value.data[1].value[index] = 0;
num: "337-TA-1392", }
area: "制造业", });
status: "正在调查",
releaseDate: "2025年8月15日"
},
{
name: "301",
title: "某些Topcon太阳能电池,模块,面板,组件及其组件和包含相同产品",
num: "337-TA-1422和337-TA-1425(合并)",
area: "半导体",
status: "正在调查",
releaseDate: "2025年8月10日"
},
{
name: "337",
title: "某些光伏干线总线电缆组件及其组件",
num: "337-TA-1438",
area: "光伏",
status: "正在调查",
releaseDate: "2025年7月29日"
},
{
name: "337",
title: "某些外国制造的半导体器件、包含相同产品及其组件的组件",
num: "337-TA-1443",
area: "半导体",
status: "正在调查",
releaseDate: "2025年7月18日"
},
{
name: "301",
title: "某些车辆远程信息处理、车队管理以及基于视频的安全系统、设备及其组件",
num: "337-TA-1441",
area: "半导体",
status: "终止调查",
releaseDate: "2025年7月1日"
},
{
name: "337",
title: "某些包含相同功能的无线前端模块和设备",
num: "337-TA-1435",
area: "半导体",
status: "正在调查",
releaseDate: "2025年6月14日"
},
{
name: "337",
title: "用于液晶显示器的某些玻璃基板,含有相同产品的产品以及制造相同方法的玻璃基板",
num: "337-TA-1433",
area: "显示技术",
status: "正在调查",
releaseDate: "2025年6月5日"
},
{
name: "337",
title: "某些Topcon太阳能电池,模块,面板,组件及其组件和包含相同产品",
num: "337-TA-1422和337-TA-1425(合并)",
area: "光伏",
status: "终止调查",
releaseDate: "2025年8月10日"
},
{
name: "232",
title: "某些蒸发器设备,其中使用的墨盒及其组件(II)",
num: "337-TA-1392",
area: "制造业",
status: "终止调查",
releaseDate: "2025年8月15日"
}
]);
// 新闻资讯 const arr3 = res.data.filter(item => {
const newsList = ref([ return item.SORTNAME === "301调查";
{ });
img: News1, const arr3Name = arr3.map(item => {
title: "美政府停摆仍持续,拨款法案存缺陷,但两党磋商露曙光", return item.AREANAME;
content: `美国政府停摆已持续34天,距离历史上最长的停摆纪录仅差一天,参议院已先后13次尝试...`, });
from: "11-4 · 华盛顿邮报" box6Data.value.title.forEach((item, index) => {
}, if (arr3Name.indexOf(item) > -1) {
{ const idx = arr3Name.indexOf(item);
img: News2, box6Data.value.data[2].value[index] = arr3[idx].AREACOUNT;
title: "美参议院通过决议,要求终止特朗普全球关税政策", } else {
content: `参议院以51票赞成、47票反对通过一项决议,旨在终止特朗普实施的全面关税政策,四名......`, box6Data.value.data[2].value[index] = 0;
from: "11-4 · 纽约时报" }
}, });
{
img: News3,
title: "美众院通过950亿美元对外援助法案,包含对台军援",
content: `国会众议院在4月通过了大规模对外援助法案,其中包括为“印太安全”提供资金的条款,......`,
from: "11-3 · 洛杉矶时报"
},
{
img: News4,
title: "“大而美”法案在激烈争议中通过",
content: `特朗普力推的大规模税收与支出法案在国会以微弱优势通过。该法案因大幅削减医疗补助和......`,
from: "11-3 · 今日美国"
},
{
img: News5,
title: "美政府“停摆”追平历史最长纪录,民生多领域受重创",
content: `联邦政府“停摆”进入第35天,追平历史纪录。食品救济项目资金中断,数百万低收入民......`,
from: "11-2 · ​福克斯新闻网"
}
]);
// 社交媒体 const numArr = res.data.map(item => {
const messageList = ref([ return item.AREACOUNT;
{ });
img: Message1,
name: "唐纳德·特朗普",
time: "15:23 · 发布于真实社交",
content: `埃隆·马斯克在强力支持我竞选总统之前,早就知道我强烈反对‘电动汽车强制令’。这太荒谬了,这一直是我竞选活动的主要部分。电动汽车没问题,但不应该强迫每个人都拥有一辆。埃隆获得的补贴可能远远超过历史上任何一个人。如果没有补贴,埃隆可能不得不关门大吉,回到南非老家。`
},
{
img: Message2,
name: "埃隆·马斯克",
time: "14:49 · 发布于X",
content: `如果这个疯狂的支出法案获得通过,‘美国党’将在第二天成立。`
},
{
img: Message3,
name: "塞巴斯蒂安·马拉比",
time: "11:05 · 发布于X",
content: `提出特朗普政府的AI政策强调技术开放与快速应用,但可能以牺牲安全防范为代价,开启了“潘多拉魔盒”。`
}
]);
// 查看更多风险信号 box6Data.value.maxNum = Math.max(...numArr);
const handleToMoreRiskSignal = () => { }
const route = router.resolve("/riskSignal"); } catch (error) {}
window.open(route.href, "_blank");
}; };
// 查看更多新闻资讯 const handleBox6 = async () => {
const handleToMoreNews = () => { await handleGetStatArea();
const route = router.resolve("/newsBrief"); let chart2 = getRadarChart(box6Data.value);
window.open(route.href, "_blank"); setChart(chart2, "chart2");
}; };
// 制裁领域分布 const box7YearList = ref([
const box6SelectedYear = ref("2025");
const box6YearList = ref([
{ {
label: "2025", label: "2025",
value: "2025" value: "2025"
...@@ -930,6 +1097,12 @@ const box6YearList = ref([ ...@@ -930,6 +1097,12 @@ const box6YearList = ref([
} }
]); ]);
const box7SelectedYear = ref("2025");
const handleChangeBox7Year = () => {
handleGetBox7Data2();
};
const box7Chart1Data = ref([ const box7Chart1Data = ref([
{ {
name: "337调查", name: "337调查",
...@@ -972,96 +1145,282 @@ const box7Chart1Data = ref([ ...@@ -972,96 +1145,282 @@ const box7Chart1Data = ref([
} }
]); ]);
const box7Chart2Data = ref([ const box7Chart2Data = ref([]);
{ const handleGetBox7Data2 = async () => {
name: "广东省", const params = {
value: 42 years: box7SelectedYear.value
}, };
{ try {
name: "上海市", const res = await getCompanyPlace(params);
value: 35 console.log("企业地域分布", res);
}, if (res.code === 200 && res.data) {
{ box7Chart2Data.value = res.data
name: "浙江省", .filter(item => {
value: 28 return item.ORGPROVINCE;
}, })
{ .map(item => {
name: "江苏省", return {
value: 19 name: item.ORGPROVINCE,
}, value: item.PROVINCECOUNT
};
});
let box7Chart2 = getBarChart(box7Chart2Data.value);
setChart(box7Chart2, "box7Chart2");
} else {
box7Chart2Data.value = [];
}
} catch (error) {}
};
handleGetBox7Data2();
// 制裁领域分布企业分布
const box8Data = ref([
// {
// logo: Logo1,
// name: "华为技术有限公司",
// data337: 12,
// data301: 2,
// data232: 1
// },
// {
// logo: Logo2,
// name: "大疆创新科技有限公司",
// data337: 7,
// data301: 1,
// data232: null
// },
// {
// logo: Logo3,
// name: "TCL科技集团股份有限公司",
// data337: 6,
// data301: 1,
// data232: null
// },
// {
// logo: Logo4,
// name: "中兴通讯股份有限公司",
// data337: 6,
// data301: null,
// data232: null
// },
// {
// logo: Logo5,
// name: "联想集团",
// data337: 6,
// data301: null,
// data232: null
// }
]);
const handleGetBox8Data = async () => {
try {
const res = await getStatAreaCompanyList();
console.log("制裁领域分布-企业分布", res);
if (res.code === 200 && res.data) {
const arr = res.data.map(item => {
return item.ORGNAME;
});
const nameArr = [...new Set(arr)];
console.log("nameArr", nameArr);
box8Data.value = Array.from({ length: nameArr.length }, () => ({
name: "",
data337: null,
data232: null,
data301: null,
logo: null
}));
nameArr.forEach((item, index) => {
box8Data.value[index].name = item;
box8Data.value[index].data337 = null;
box8Data.value[index].data301 = null;
box8Data.value[index].data232 = null;
box8Data.value[index].logo = null;
});
box8Data.value.forEach(item => {
res.data.forEach(val => {
if (val.ORGNAME === item.name && val.SORTCODE === "337") {
item.data337 = val.ORGCOUNT;
}
if (val.ORGNAME === item.name && val.SORTCODE === "232") {
item.data232 = val.ORGCOUNT;
}
if (val.ORGNAME === item.name && val.SORTCODE === "302") {
item.data301 = val.ORGCOUNT;
}
});
});
console.log("box8Data", box8Data.value);
}
} catch (error) {
console.error(error);
}
};
// 资源库
const pageSize = ref(10);
const currentPage = ref(1);
const totalDiscussNum = ref(0);
const handleCurrentChange = page => {
currentPage.value = page;
handleGetSurveyList();
};
const categoryList = ref([
{ {
name: "北京市", name: "全部调查",
value: 15 id: ""
}, },
{ {
name: "四川省", name: "301调查",
value: 12 id: "301"
}, },
{ {
name: "山东省", name: "232调查",
value: 11 id: "232"
}, },
{ {
name: "福建省", name: "337调查",
value: 8 id: "337"
} }
]); ]);
const box8Data = ref([ const activeCateId = ref("");
const handleClickCate = cate => {
activeCateId.value = cate.id;
handleGetSurveyList();
};
const isSort = ref(true); // true 升序 false 倒序
const handleSwithSort = () => {
isSort.value = !isSort.value;
};
const surveyYearList = ref([
{ {
logo: Logo1, name: "2025年",
name: "华为技术有限公司", id: "2025"
data337: 12,
data301: 2,
data232: 1
}, },
{ {
logo: Logo2, name: "2024年",
name: "大疆创新科技有限公司", id: "2024"
data337: 7,
data301: 1,
data232: null
}, },
{ {
logo: Logo3, name: "2023年",
name: "TCL科技集团股份有限公司", id: "2023"
data337: 6,
data301: 1,
data232: null
}, },
{ {
logo: Logo4, name: "2022年",
name: "中兴通讯股份有限公司", id: "2022"
data337: 6,
data301: null,
data232: null
}, },
{ {
logo: Logo5, name: "2021年",
name: "联想集团", id: "2021"
data337: 6,
data301: null,
data232: null
} }
]); ]);
onMounted(async () => { const checkedSurveyYears = ref(["2025"]);
let chart1 = getMultiLineChart( const handleChangeCheckedSurveyYears = () => {
chart1Data.value.title, // console.log(checkedSurveyYears.value);
chart1Data.value.data[0].value, handleGetSurveyList();
chart1Data.value.data[1].value, };
chart1Data.value.data[2].value
);
setChart(chart1, "chart1");
let chart2 = getRadarChart(); const areaList = ref([
setChart(chart2, "chart2"); // { id: "人工智能", name: "人工智能" },
]);
const checkedAreaList = ref(["1"]);
const handleGetAreaList = async () => {
try {
const res = await getHylyList();
console.log("行业领域列表", res);
if (res.code === 200 && res.data) {
areaList.value = res.data.map(item => {
return {
name: item.name,
id: item.id
};
});
console.log("areaList", areaList.value);
}
} catch (error) {}
};
const handleChangeCheckedAreas = () => {
// console.log(checkedAreaList.value);
handleGetSurveyList();
};
const surveyInfoList = ref([
]);
const handleGetSurveyList = async () => {
const params = {
currentPage: currentPage.value - 1,
pageSize: pageSize.value,
sortCode: activeCateId.value,
publishYear: checkedSurveyYears.value.toString(),
Area: checkedAreaList.value.toString(),
sortField: "date",
sortOrder: isSort.value ? "asc" : "desc"
};
try {
const res = await getSurveyList(params);
console.log("调查列表", res);
if (res.code === 200 && res.data) {
totalDiscussNum.value = res.data.totalElements;
surveyInfoList.value = res.data.content;
} else {
surveyInfoList.value = [];
ElMessage.warning("当前条件下无调查列表数据!");
}
} catch (error) {}
};
const handleClickToSurveyDetail = (id) => {
const route = router.resolve({
path: "/marketAccessLayout",
query: {
id: id
}
});
window.open(route.href, "_blank");
};
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
window.open(route.href, "_blank");
};
// 查看更多新闻资讯
const handleToMoreNews = () => {
const route = router.resolve("/newsBrief");
window.open(route.href, "_blank");
};
// 返回首页
const handleBackHome = () => {
router.push({
path: "/overview"
});
};
onMounted(async () => {
handleGetBox1Data();
handleGetStatSort();
handleGetBox2Data();
handleGetBox3Data();
handleGetBox4Data();
handleBox5();
handleBox6();
handleGetBox8Data();
let box7Chart1 = getMapChart(box7Chart1Data.value); let box7Chart1 = getMapChart(box7Chart1Data.value);
setChart(box7Chart1, "box7Chart1"); setChart(box7Chart1, "box7Chart1");
let box7Chart2 = getBarChart(box7Chart2Data.value); await handleGetAreaList();
setChart(box7Chart2, "box7Chart2"); handleGetSurveyList();
}); });
</script> </script>
...@@ -1288,6 +1647,7 @@ onMounted(async () => { ...@@ -1288,6 +1647,7 @@ onMounted(async () => {
.content-box { .content-box {
margin-left: 30px; margin-left: 30px;
.item { .item {
width: 485px;
height: 24px; height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -1295,6 +1655,9 @@ onMounted(async () => { ...@@ -1295,6 +1655,9 @@ onMounted(async () => {
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
margin-top: 8px; margin-top: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
} }
} }
...@@ -1346,6 +1709,7 @@ onMounted(async () => { ...@@ -1346,6 +1709,7 @@ onMounted(async () => {
.content-box { .content-box {
margin-left: 30px; margin-left: 30px;
.item { .item {
width: 485px;
height: 24px; height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -1353,6 +1717,9 @@ onMounted(async () => { ...@@ -1353,6 +1717,9 @@ onMounted(async () => {
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
margin-top: 8px; margin-top: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
} }
} }
...@@ -1405,6 +1772,7 @@ onMounted(async () => { ...@@ -1405,6 +1772,7 @@ onMounted(async () => {
.content-box { .content-box {
margin-left: 30px; margin-left: 30px;
.item { .item {
width: 485px;
height: 24px; height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -1412,6 +1780,9 @@ onMounted(async () => { ...@@ -1412,6 +1780,9 @@ onMounted(async () => {
font-weight: 400; font-weight: 400;
line-height: 24px; line-height: 24px;
margin-top: 8px; margin-top: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
} }
} }
...@@ -1436,6 +1807,7 @@ onMounted(async () => { ...@@ -1436,6 +1807,7 @@ onMounted(async () => {
.box1-left { .box1-left {
position: absolute; position: absolute;
left: 0; left: 0;
z-index: 9999;
top: 220px; top: 220px;
width: 24px; width: 24px;
height: 48px; height: 48px;
...@@ -1449,6 +1821,7 @@ onMounted(async () => { ...@@ -1449,6 +1821,7 @@ onMounted(async () => {
position: absolute; position: absolute;
right: 0; right: 0;
top: 220px; top: 220px;
z-index: 9999;
width: 24px; width: 24px;
height: 48px; height: 48px;
cursor: pointer; cursor: pointer;
...@@ -1519,8 +1892,9 @@ onMounted(async () => { ...@@ -1519,8 +1892,9 @@ onMounted(async () => {
} }
.header-right { .header-right {
display: flex; display: flex;
width: 200px; width: 300px;
justify-content: flex-end; justify-content: flex-end;
flex-wrap: wrap;
.tag1 { .tag1 {
height: 24px; height: 24px;
line-height: 24px; line-height: 24px;
...@@ -1575,6 +1949,7 @@ onMounted(async () => { ...@@ -1575,6 +1949,7 @@ onMounted(async () => {
line-height: 24px; line-height: 24px;
} }
.title { .title {
width: 200px;
margin-left: 11px; margin-left: 11px;
margin-top: 10px; margin-top: 10px;
height: 24px; height: 24px;
...@@ -1588,6 +1963,8 @@ onMounted(async () => { ...@@ -1588,6 +1963,8 @@ onMounted(async () => {
.info-content { .info-content {
width: 909px; width: 909px;
height: 60px; height: 60px;
overflow: hidden;
overflow-y: auto;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
...@@ -1602,8 +1979,10 @@ onMounted(async () => { ...@@ -1602,8 +1979,10 @@ onMounted(async () => {
margin-left: 28px; margin-left: 28px;
width: 940px; width: 940px;
height: 185px; height: 185px;
overflow: hidden;
overflow-y: auto;
.list-item { .list-item {
height: 37px; min-height: 37px;
display: flex; display: flex;
.icon { .icon {
width: 4px; width: 4px;
...@@ -1708,9 +2087,9 @@ onMounted(async () => { ...@@ -1708,9 +2087,9 @@ onMounted(async () => {
&:hover { &:hover {
background: var(--color-bg-hover); background: var(--color-bg-hover);
} }
.itemLeftStatus1 { .itemLeftStatus3 {
color: rgba(82, 196, 26, 1) !important; background: rgba(255, 241, 240) !important;
background: rgba(246, 255, 237, 1) !important; color: rgba(245, 34, 45, 1) !important;
} }
.itemLeftStatus2 { .itemLeftStatus2 {
color: rgba(250, 140, 22, 1) !important; color: rgba(250, 140, 22, 1) !important;
...@@ -1722,8 +2101,8 @@ onMounted(async () => { ...@@ -1722,8 +2101,8 @@ onMounted(async () => {
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 20px; border-radius: 20px;
background: rgba(255, 241, 240); color: rgba(82, 196, 26, 1);
color: rgba(245, 34, 45, 1); background: rgba(246, 255, 237, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
...@@ -1739,15 +2118,18 @@ onMounted(async () => { ...@@ -1739,15 +2118,18 @@ onMounted(async () => {
border-bottom: 1px solid rgba(240, 242, 244, 1); border-bottom: 1px solid rgba(240, 242, 244, 1);
display: flex; display: flex;
.text { .text {
width: 348px; width: 328px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
line-height: 47px; line-height: 47px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.time { .time {
margin-left: 10px; margin-left: 2px;
line-height: 47px; line-height: 47px;
color: rgba(132, 136, 142, 1); color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -1855,6 +2237,10 @@ onMounted(async () => { ...@@ -1855,6 +2237,10 @@ onMounted(async () => {
width: 749px; width: 749px;
margin-left: 21px; margin-left: 21px;
border-bottom: 1px solid rgba(240, 242, 244, 1); border-bottom: 1px solid rgba(240, 242, 244, 1);
cursor: pointer;
&:hover {
background: var(--color-bg-hover);
}
.left { .left {
width: 72px; width: 72px;
height: 48px; height: 48px;
...@@ -1873,7 +2259,7 @@ onMounted(async () => { ...@@ -1873,7 +2259,7 @@ onMounted(async () => {
justify-content: space-between; justify-content: space-between;
.title { .title {
margin-top: 13px; margin-top: 13px;
width: 520px; width: 470px;
height: 24px; height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -1885,15 +2271,18 @@ onMounted(async () => { ...@@ -1885,15 +2271,18 @@ onMounted(async () => {
white-space: nowrap; white-space: nowrap;
} }
.time { .time {
flex: 1; width: 187px;
text-align: right; text-align: right;
height: 22px; height: 22px;
margin-top: 19px; margin-top: 15px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 22px; line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
} }
.right-footer { .right-footer {
...@@ -1962,6 +2351,7 @@ onMounted(async () => { ...@@ -1962,6 +2351,7 @@ onMounted(async () => {
} }
.box4-main { .box4-main {
height: 402px; height: 402px;
overflow: hidden;
overflow-y: auto; overflow-y: auto;
box-sizing: border-box; box-sizing: border-box;
padding-top: 8px; padding-top: 8px;
...@@ -1973,6 +2363,9 @@ onMounted(async () => { ...@@ -1973,6 +2363,9 @@ onMounted(async () => {
margin-top: 5px; margin-top: 5px;
width: 36px; width: 36px;
height: 36px; height: 36px;
border-radius: 18px;
overflow: hidden;
cursor: pointer;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -2512,7 +2905,8 @@ onMounted(async () => { ...@@ -2512,7 +2905,8 @@ onMounted(async () => {
} }
.home-main-footer { .home-main-footer {
// width: 100%; // width: 100%;
height: 1149px; // height: 1149px;
padding-bottom: 20px;
background: rgba(248, 249, 250, 1); background: rgba(248, 249, 250, 1);
overflow: hidden; overflow: hidden;
.home-main-footer-header { .home-main-footer-header {
...@@ -2555,27 +2949,70 @@ onMounted(async () => { ...@@ -2555,27 +2949,70 @@ onMounted(async () => {
height: 42px; height: 42px;
box-sizing: border-box; box-sizing: border-box;
padding: 5px 0; padding: 5px 0;
.paixu-btn {
display: flex;
width: 120px;
height: 32px;
box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 4px;
background: rgba(255, 255, 255, 1);
&:hover {
background: var(--color-bg-hover);
}
cursor: pointer;
.icon1 {
width: 11px;
height: 14px;
margin-top: 10px;
margin-left: 9px;
img {
width: 100%;
height: 100%;
}
}
.text {
height: 19px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0px;
text-align: left;
margin-top: 7px;
margin-left: 9px;
}
.icon2 {
width: 10px;
height: 5px;
margin-top: 5px;
margin-left: 13px;
img {
width: 100%;
height: 100%;
}
}
}
} }
} }
.home-main-footer-main { .home-main-footer-main {
width: 1600px; width: 1600px;
margin-bottom: 20px; margin-bottom: 20px;
height: 985px; // height: 985px;
// box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
// background: rgba(255, 255, 255, 1);
margin: 0 auto; margin: 0 auto;
box-sizing: border-box; box-sizing: border-box;
// padding: 20px; // padding: 20px;
display: flex; display: flex;
.left { .left {
width: 300px; width: 300px;
height: 560px; height: 700px;
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
.left-box1 { .left-box1 {
margin-top: 17px; margin-top: 17px;
height: 260px; height: 220px;
.left-box1-header { .left-box1-header {
display: flex; display: flex;
.icon { .icon {
...@@ -2597,10 +3034,7 @@ onMounted(async () => { ...@@ -2597,10 +3034,7 @@ onMounted(async () => {
} }
.left-box1-main { .left-box1-main {
margin-top: 10px; margin-top: 10px;
.time-label { padding-left: 20px;
height: 35px;
margin-left: 25px;
}
} }
} }
.left-box2 { .left-box2 {
...@@ -2627,17 +3061,15 @@ onMounted(async () => { ...@@ -2627,17 +3061,15 @@ onMounted(async () => {
} }
.left-box2-main { .left-box2-main {
margin-top: 10px; margin-top: 10px;
.area-label { padding-left: 20px;
height: 35px;
margin-left: 25px;
}
} }
} }
} }
.right { .right {
margin-left: 16px; margin-left: 16px;
width: 1284px; width: 1284px;
height: 899px; min-height: 700px;
// height: 899px;
border-radius: 10px; border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2); box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
...@@ -2698,12 +3130,16 @@ onMounted(async () => { ...@@ -2698,12 +3130,16 @@ onMounted(async () => {
} }
} }
.right-main { .right-main {
height: 780px; min-height: 586px;
// background: orange; border-bottom: 1px solid rgba(230, 231, 232, 1);
// height: 780px;
.item { .item {
display: flex; display: flex;
padding: 16px 0; padding: 16px 0;
// height: 56px; cursor: pointer;
&:hover{
background: var(--color-bg-hover) !important;
}
&:nth-child(2n) { &:nth-child(2n) {
background: rgba(247, 248, 249, 1); background: rgba(247, 248, 249, 1);
} }
...@@ -2797,9 +3233,10 @@ onMounted(async () => { ...@@ -2797,9 +3233,10 @@ onMounted(async () => {
} }
} }
.right-footer { .right-footer {
box-sizing: border-box;
padding-top: 15px;
height: 60px;
display: flex; display: flex;
// height: 60px;
// background: orange;
justify-content: space-between; justify-content: space-between;
.footer-left { .footer-left {
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
......
...@@ -8,7 +8,7 @@ const getBarChart = (originalData) => { ...@@ -8,7 +8,7 @@ const getBarChart = (originalData) => {
tooltip: {}, tooltip: {},
grid: { grid: {
top: '3%', top: '3%',
right: '3%', right: 66,
bottom: '1%', bottom: '1%',
left: '1%', left: '1%',
containLabel: true containLabel: true
......
import * as echarts from 'echarts' import * as echarts from 'echarts'
const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { const getMultiLineChart = (data) => {
console.log('dataaaa',data);
return { return {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
...@@ -13,9 +15,9 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -13,9 +15,9 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
}, },
grid: { grid: {
top: '15%', top: '15%',
right: '5%', right: '3%',
bottom: '5%', bottom: '5%',
left: '5%', left: '3%',
containLabel: true containLabel: true
}, },
legend: { legend: {
...@@ -28,7 +30,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -28,7 +30,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
{ {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: dataX data: data.title
} }
], ],
yAxis: [ yAxis: [
...@@ -38,7 +40,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -38,7 +40,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
], ],
series: [ series: [
{ {
name: '337调查', name: data.data[0].name,
type: 'line', type: 'line',
areaStyle: { areaStyle: {
...@@ -53,10 +55,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -53,10 +55,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
emphasis: { emphasis: {
focus: 'series' focus: 'series'
}, },
data: dataY1 data: data.data[0].value
}, },
{ {
name: '301调查', name: data.data[1].name,
type: 'line', type: 'line',
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
...@@ -70,10 +72,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -70,10 +72,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
emphasis: { emphasis: {
focus: 'series' focus: 'series'
}, },
data: dataY2 data: data.data[1].value,
}, },
{ {
name: '232调查', name: data.data[2].name,
type: 'line', type: 'line',
areaStyle: { areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
...@@ -87,7 +89,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -87,7 +89,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
emphasis: { emphasis: {
focus: 'series' focus: 'series'
}, },
data: dataY3 data: data.data[2].value,
} }
] ]
} }
......
const getRadarChart = () => { const getRadarChart = (data) => {
const indicators = [ // const indicators = [
{ name: "集成电路", max: 10 }, // { name: "集成电路", max: 10 },
{ name: "能源领域", max: 10 }, // { name: "能源领域", max: 10 },
{ name: "量子科技", max: 10 }, // { name: "量子科技", max: 10 },
{ name: "通信网络", max: 10 }, // { name: "通信网络", max: 10 },
{ name: "人工智能", max: 10 }, // { name: "人工智能", max: 10 },
{ name: "生物科技", max: 10 } // { name: "生物科技", max: 10 }
]; // ];
const indicators = data.title.map(item => {
return {
name: item, max: data.maxNum
}
})
const data337 = [9, 6, 6, 6, 9, 7]; const data337 = [9, 6, 6, 6, 9, 7];
const data301 = [5, 3, 7, 8, 7, 9]; const data301 = [5, 3, 7, 8, 7, 9];
const data232 = [4, 10, 3, 4, 2, 5]; const data232 = [4, 10, 3, 4, 2, 5];
...@@ -67,9 +72,10 @@ const getRadarChart = () => { ...@@ -67,9 +72,10 @@ const getRadarChart = () => {
}, },
series: [ series: [
{ {
name: "337调查", // name: "337调查",
name: data.data[0].name,
type: "radar", type: "radar",
data: [{ value: data337 }], data: [{ value: data.data[0].value }],
lineStyle: { lineStyle: {
width: 2, width: 2,
color: "rgba(5, 95, 194,1)" color: "rgba(5, 95, 194,1)"
...@@ -80,9 +86,9 @@ const getRadarChart = () => { ...@@ -80,9 +86,9 @@ const getRadarChart = () => {
} }
}, },
{ {
name: "301调查", name: data.data[1].name,
type: "radar", type: "radar",
data: [{ value: data301 }], data: [{ value: data.data[1].value }],
lineStyle: { lineStyle: {
width: 2, width: 2,
color: "rgba(250, 140, 22, 1)" color: "rgba(250, 140, 22, 1)"
...@@ -93,9 +99,9 @@ const getRadarChart = () => { ...@@ -93,9 +99,9 @@ const getRadarChart = () => {
} }
}, },
{ {
name: "232调查", name: data.data[2].name,
type: "radar", type: "radar",
data: [{ value: data232 }], data: [{ value: data.data[2].value }],
lineStyle: { lineStyle: {
width: 2, width: 2,
color: "rgba(146, 84, 222, 1)" color: "rgba(146, 84, 222, 1)"
......
...@@ -3,19 +3,24 @@ ...@@ -3,19 +3,24 @@
<div class="header"> <div class="header">
<div class="header-top"> <div class="header-top">
<div class="header-top-left"> <div class="header-top-left">
<div class="title">{{ "中美经济竞争:复杂经济和地缘政治关系中的收益和风险" }}</div> <img :src="thinkInfo.contentUrl" alt="" />
<div class="en-title"> <div>
{{ "U.S.-China Economic CompetitionGains and Risks in a Complex Economic and Geopolitical Relationship" }} <div class="title">{{ thinkInfo.name }}</div>
</div> <div class="en-title">
<div class="tag-box"> {{ thinkInfo.ename }}
<div class="tag">{{ "外交" }}</div> </div>
<div class="tag">{{ "军事" }}</div> <div style="display: flex;">
<div class="tag">{{ "经济" }}</div> <div class="tag-box" v-for="value in thinkInfo.tags">
<div class="tag">{{ value.industryName }}</div>
</div>
</div>
</div> </div>
</div> </div>
<div class="header-top-right"> <div class="header-top-right">
<div class="name">{{ "兰德科技智库" }}</div> <div class="name">{{ thinkInfo.thinkTankName }}</div>
<div class="time">{{ "2025年6月23日" }}</div> <div class="time">{{ thinkInfo.times }}</div>
</div> </div>
</div> </div>
<div class="header-bottom"> <div class="header-bottom">
...@@ -81,6 +86,9 @@ import { ...@@ -81,6 +86,9 @@ import {
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
const router = useRouter(); const router = useRouter();
const reportUrl = ref('') const reportUrl = ref('')
const thinkInfo = ref({})
// 获取报告全局信息 // 获取报告全局信息
const handleGetThinkTankReportSummary = async () => { const handleGetThinkTankReportSummary = async () => {
try { try {
...@@ -89,6 +97,7 @@ const handleGetThinkTankReportSummary = async () => { ...@@ -89,6 +97,7 @@ const handleGetThinkTankReportSummary = async () => {
console.log("报告全局信息", res); console.log("报告全局信息", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
reportUrl.value = res.data.reportUrl reportUrl.value = res.data.reportUrl
thinkInfo.value = res.data
} }
} catch (error) { } catch (error) {
console.error("获取报告全局信息error", error); console.error("获取报告全局信息error", error);
...@@ -96,7 +105,15 @@ const handleGetThinkTankReportSummary = async () => { ...@@ -96,7 +105,15 @@ const handleGetThinkTankReportSummary = async () => {
}; };
const toReport = () => { const toReport = () => {
window.open(reportUrl.value, "_blank"); console.log(reportUrl.value, 'reportUrl.valuereportUrl.value')
const route = router.resolve({
name: "ReportOriginal",
params: {
id: router.currentRoute._value.params.id
}
});
window.open(route.href, "_blank");
} }
const tabActiveName = ref("报告分析"); const tabActiveName = ref("报告分析");
...@@ -124,13 +141,21 @@ onMounted(async () => { ...@@ -124,13 +141,21 @@ onMounted(async () => {
.header-top { .header-top {
margin-top: 20px; margin-top: 20px;
margin-left: 248px; margin-left: 160px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
margin-right: 160px; margin-right: 160px;
.header-top-left { .header-top-left {
display: flex;
img {
width: 72px;
height: 88px;
}
.title { .title {
margin-left: 20px;
height: 26px; height: 26px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -142,6 +167,7 @@ onMounted(async () => { ...@@ -142,6 +167,7 @@ onMounted(async () => {
} }
.en-title { .en-title {
margin-left: 20px;
height: 24px; height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -156,6 +182,7 @@ onMounted(async () => { ...@@ -156,6 +182,7 @@ onMounted(async () => {
margin-top: 11px; margin-top: 11px;
display: flex; display: flex;
gap: 8px; gap: 8px;
margin-left: 20px;
.tag { .tag {
height: 26px; height: 26px;
......
...@@ -43,14 +43,14 @@ ...@@ -43,14 +43,14 @@
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <!-- <div class="right">
<div class="text"> <div class="text">
{{ "查看智库原文" }} {{ "查看智库原文" }}
</div> </div>
<div class="icon"> <div class="icon">
<img src="@/assets/icons/open.png" alt="" /> <img src="@/assets/icons/open.png" alt="" />
</div> </div>
</div> </div> -->
</div> </div>
</div> </div>
...@@ -76,26 +76,26 @@ ...@@ -76,26 +76,26 @@
<div class="point"> <div class="point">
<img src="@/assets/images/dot.png" alt="" /> <img src="@/assets/images/dot.png" alt="" />
</div> </div>
<div class="line" v-if="index < 5"></div> <div class="line"></div>
</div> </div>
<div class="box2-item-center"> <div class="box2-item-center">
<div class="title">{{ item.sjbt }}</div> <div class="title">{{ item.newsTitle }}</div>
<div class="content">{{ item.sjnr }}</div> <div class="content">{{ item.newsContent }}</div>
</div> </div>
<div class="box2-item-right"> <div class="box2-item-right">
<div class="time">{{ item.time }}</div> <div class="time">{{ item.newsDate }}</div>
<div class="img-box"> <div class="img-box">
<img :src="item.imageUrl" alt="" /> <img :src="item.newsImage" alt="" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="box2-footer"> <!-- <div class="box2-footer">
<div class="text">{{ "查看更多" }}</div> <div class="text">{{ "查看更多" }}</div>
<div class="icon"> <div class="icon">
<img src="@/assets/images/icon-double-down.png" alt="" /> <img src="@/assets/images/icon-double-down.png" alt="" />
</div> </div>
</div> </div> -->
</div> </div>
</div> </div>
</template> </template>
...@@ -277,42 +277,42 @@ const handleGetThinkTankReportPolicy = async () => { ...@@ -277,42 +277,42 @@ const handleGetThinkTankReportPolicy = async () => {
// 相关政策动态 // 相关政策动态
const box2Data = ref([ const box2Data = ref([
{ // {
title: "这是示例标题a", // title: "这是示例标题a",
content: "这是示例内容", // content: "这是示例内容",
time: "2025-08-30", // time: "2025-08-30",
img: 1 // img: 1
}, // },
{ // {
title: "这是示例标题a", // title: "这是示例标题a",
content: "这是示例内容", // content: "这是示例内容",
time: "2025-08-30", // time: "2025-08-30",
img: 1 // img: 1
}, // },
{ // {
title: "这是示例标题a", // title: "这是示例标题a",
content: "这是示例内容", // content: "这是示例内容",
time: "2025-08-30", // time: "2025-08-30",
img: 1 // img: 1
}, // },
{ // {
title: "这是示例标题a", // title: "这是示例标题a",
content: "这是示例内容", // content: "这是示例内容",
time: "2025-08-30", // time: "2025-08-30",
img: 1 // img: 1
}, // },
{ // {
title: "这是示例标题a", // title: "这是示例标题a",
content: "这是示例内容", // content: "这是示例内容",
time: "2025-08-30", // time: "2025-08-30",
img: 1 // img: 1
}, // },
{ // {
title: "这是示例标题a", // title: "这是示例标题a",
content: "这是示例内容", // content: "这是示例内容",
time: "2025-08-30", // time: "2025-08-30",
img: 1 // img: 1
} // }
]); ]);
const handleGetThinkTankReportPolicyAction = async () => { const handleGetThinkTankReportPolicyAction = async () => {
...@@ -429,13 +429,16 @@ onMounted(async () => { ...@@ -429,13 +429,16 @@ onMounted(async () => {
.box1-main { .box1-main {
width: 1056px; width: 1056px;
height: 1280px; min-height: 738px;
max-height: 1280px;
padding-bottom: 20px;
margin: 0 auto; margin: 0 auto;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
.box1-item { .box1-item {
height: 128px; align-items: center;
// height: 128px;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex; display: flex;
position: relative; position: relative;
...@@ -462,7 +465,7 @@ onMounted(async () => { ...@@ -462,7 +465,7 @@ onMounted(async () => {
.title { .title {
margin-top: 16px; margin-top: 16px;
height: 24px; // height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 18px; font-size: 18px;
......
...@@ -38,12 +38,12 @@ ...@@ -38,12 +38,12 @@
</div> </div>
</div> </div>
<div class="box2-main"> <div class="box2-main">
<div class="box2-main-tag-box"> <!-- <div class="box2-main-tag-box">
<div class="tag" :class="{ tagActive: activeArea === item }" v-for="(item, index) in areaList" :key="index" <div class="tag" :class="{ tagActive: activeArea === item }" v-for="(item, index) in areaList" :key="index"
@click="handleClickArea(item.status)"> @click="handleClickArea(item.status)">
{{ item.industryName }} {{ item.industryName }}
</div> </div>
</div> </div> -->
<div class="box2-content" id="box2Chart"></div> <div class="box2-content" id="box2Chart"></div>
</div> </div>
</div> </div>
...@@ -82,10 +82,10 @@ ...@@ -82,10 +82,10 @@
</div> </div>
<div class="right"> <div class="right">
<div class="tag" v-for="(val, idx) in item.hylyList" :key="idx"> <div class="tag" v-for="(val, idx) in item.hylyList" :key="idx">
{{ val.name }} {{ val }}
</div> </div>
<div class="tag" v-for="(val, idx) in item.serialNum" :key="idx"> <div class="tag" v-for="(val, idx) in item.serialNum" :key="idx">
{{ val.name }} {{ val }}
</div> </div>
</div> </div>
<div class="more"> <div class="more">
...@@ -94,7 +94,7 @@ ...@@ -94,7 +94,7 @@
</div> </div>
</div> </div>
<div class="box3-main-footer"> <div class="box3-main-footer">
<div class="info">{{ total }}项调查</div> <div class="info">{{ total }}条建议</div>
<div class="page-box"> <div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total" <el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" /> @current-change="handleCurrentChange" :current-page="currentPage" />
...@@ -197,7 +197,7 @@ const handleGetThinkTankReportIndustryCloud = async () => { ...@@ -197,7 +197,7 @@ const handleGetThinkTankReportIndustryCloud = async () => {
try { try {
const params = { const params = {
id: router.currentRoute._value.params.id, id: router.currentRoute._value.params.id,
industryId: activeArea.value // industryId: activeArea.value
}; };
const res = await getThinkTankReportIndustryCloud(params); const res = await getThinkTankReportIndustryCloud(params);
console.log("科技领域词云", res); console.log("科技领域词云", res);
...@@ -372,6 +372,7 @@ const majorOpinions = ref([ ...@@ -372,6 +372,7 @@ const majorOpinions = ref([
]); ]);
// 处理页码改变事件 // 处理页码改变事件
const currentPage = ref(1); const currentPage = ref(1);
const total = ref(0)
const handleCurrentChange = page => { const handleCurrentChange = page => {
currentPage.value = page; currentPage.value = page;
handleGetThinkDynamicsReport(); handleGetThinkDynamicsReport();
...@@ -380,9 +381,10 @@ const handleCurrentChange = page => { ...@@ -380,9 +381,10 @@ const handleCurrentChange = page => {
const handleGetThinkTankReportContent = async () => { const handleGetThinkTankReportContent = async () => {
try { try {
const res = await getThinkTankReportContent(router.currentRoute._value.params.id); const res = await getThinkTankReportContent(router.currentRoute._value.params.id);
console.log("主要观点", res); console.log("主要观点", res.data);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
majorOpinions.value = res.data.content; majorOpinions.value = res.data.content;
total.value = res.data.totalElements
} }
} catch (error) { } catch (error) {
console.error("获取主要观点error", error); console.error("获取主要观点error", error);
...@@ -588,7 +590,7 @@ onMounted(() => { ...@@ -588,7 +590,7 @@ onMounted(() => {
.box2-content { .box2-content {
width: 430px; width: 430px;
height: 231px; height: 315px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1); border: 1px solid rgba(234, 236, 238, 1);
border-radius: 4px; border-radius: 4px;
...@@ -644,15 +646,18 @@ onMounted(() => { ...@@ -644,15 +646,18 @@ onMounted(() => {
} }
.center { .center {
width: 770px; height: 64px;
width: 910px;
margin-left: 13px; margin-left: 13px;
overflow: hidden; display: flex;
text-overflow: ellipsis; align-items: center;
white-space: nowrap; // overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
.title { .title {
margin-top: 12px; margin-top: 12px;
height: 26px; // height: 55px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
...@@ -661,8 +666,12 @@ onMounted(() => { ...@@ -661,8 +666,12 @@ onMounted(() => {
letter-spacing: 0px; letter-spacing: 0px;
text-align: left; text-align: left;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; // text-overflow: ellipsis;
white-space: nowrap; // white-space: nowrap;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
} }
.desc { .desc {
...@@ -685,8 +694,11 @@ onMounted(() => { ...@@ -685,8 +694,11 @@ onMounted(() => {
width: 180px; width: 180px;
height: 22px; height: 22px;
display: flex; display: flex;
gap: 8px; margin-top: 26px;
justify-content: flex-end; margin-left: 20px;
height: 22px;
display: flex;
.tag { .tag {
height: 22px; height: 22px;
......
...@@ -111,34 +111,41 @@ ...@@ -111,34 +111,41 @@
<img :src="item.imageUrl" alt="" /> <img :src="item.imageUrl" alt="" />
</div> </div>
<div class="item-right"> <div class="item-right">
<div class="title">{{ item.content }}</div> <div>
<div class="info">{{ item.times }} · {{ item.name }}</div> <div class="title">{{ item.content }}</div>
<div class="tag-box"> <div class="info">{{ item.times }} · {{ item.name }}</div>
<div class="tag" v-for="(tag, idx) in item.tagList" :key="idx"> <div class="tag-box">
{{ tag }} <div class="tag" v-for="(tag, idx) in item.tagList" :key="idx">
</div> {{ tag }}
</div>
<div class="file-box">
<div class="file" v-for="(file, idxx) in item.relationBillsList" :key="idxx">
<div class="type">法案</div>
<div class="title">{{ file.billName }}</div>
<div class="more">
<img src="./images/arrow-right.png" alt="" />
</div> </div>
</div> </div>
<div class="file" v-for="(file, idxx) in item.relationAdList" :key="idxx"> <div class="file-box">
<div class="type">政令</div> <div class="file" v-for="(file, idxx) in item.relationBillsList" :key="idxx">
<div class="title">{{ file.adName }}</div> <div class="type">法案</div>
<div class="more"> <div class="title">{{ file.billName }}</div>
<img src="./images/arrow-right.png" alt="" /> <div class="more">
<img src="./images/arrow-right.png" alt="" />
</div>
</div>
<div class="file" v-for="(file, idxx) in item.relationAdList" :key="idxx">
<div class="type">政令</div>
<div class="title">{{ file.adName }}</div>
<div class="more">
<img src="./images/arrow-right.png" alt="" />
</div>
</div> </div>
</div> </div>
</div> </div>
<div>
<div class="more" @click="toDetaile(item.reportId)">
<img src="@/assets/icons/open.png" alt="" />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="right-footer"> <div class="right-footer">
<div class="info">{{ total }}智库报告</div> <div class="info">{{ total }}篇政策建议</div>
<div class="page-box"> <div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total" <el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" /> @current-change="handleCurrentChange" :current-page="currentPage" />
...@@ -528,6 +535,17 @@ function getDateMonthsAgo(months) { ...@@ -528,6 +535,17 @@ function getDateMonthsAgo(months) {
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
} }
const toDetaile = (id) => {
const route = router.resolve({
name: "ReportDetail",
params: {
id: id
}
});
window.open(route.href, "_blank");
}
const total = ref(0); const total = ref(0);
const sort = ref(true); const sort = ref(true);
const currentPage = ref(1); const currentPage = ref(1);
...@@ -813,7 +831,8 @@ onMounted(() => { ...@@ -813,7 +831,8 @@ onMounted(() => {
.right { .right {
width: 1284px; width: 1284px;
height: 1670px; max-height: 1670px;
margin-bottom: 20px;
box-sizing: border-box; box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1); border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px; border-radius: 10px;
...@@ -823,10 +842,10 @@ onMounted(() => { ...@@ -823,10 +842,10 @@ onMounted(() => {
.right-main { .right-main {
margin: 17px auto; margin: 17px auto;
width: 1209px; width: 1209px;
height: 1540px; max-height: 1540px;
.right-main-item { .right-main-item {
height: 154px; // height: 154px;
box-sizing: border-box; box-sizing: border-box;
padding-top: 8px; padding-top: 8px;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
...@@ -845,6 +864,9 @@ onMounted(() => { ...@@ -845,6 +864,9 @@ onMounted(() => {
.item-right { .item-right {
margin-left: 15px; margin-left: 15px;
display: flex;
width: 100%;
justify-content: space-between;
.title { .title {
// height: 24px; // height: 24px;
......
...@@ -21,7 +21,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => { ...@@ -21,7 +21,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
legend: { legend: {
show: true, show: true,
top: 10, top: 10,
left:'10%' left:'10%',
textStyle: {
fontSize: 16
}
}, },
xAxis: [ xAxis: [
{ {
......
...@@ -2,46 +2,53 @@ const getPieChart = (data) => { ...@@ -2,46 +2,53 @@ const getPieChart = (data) => {
let option = { let option = {
series: [ series: [
{ {
type: 'pie', type: 'pie',
radius: [70, 100], radius: [70, 100],
height: '100%', height: '100%',
left: 'center', left: 'center',
width: '100%', width: '100%',
itemStyle: { itemStyle: {
borderColor: '#fff', borderColor: '#fff',
borderWidth: 1 borderWidth: 1
}, },
label: { label: {
alignTo: 'edge', alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 条 {d}%}', formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
minMargin: 5, minMargin: 10,
edgeDistance: 10, edgeDistance: 20,
lineHeight: 15, lineHeight: 24,
rich: { rich: {
time: { name: {
fontSize: 10, fontSize: 16,
color: '#999' color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei',
fontWeight: 700
},
time: {
fontSize: 16,
color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei',
}
} }
} },
}, labelLine: {
labelLine: { length: 15,
length: 15, length2: 0,
length2: 0, maxSurfaceAngle: 80
maxSurfaceAngle: 80 },
}, labelLayout: function (params) {
labelLayout: function (params) { const isLeft = params.labelRect.x < 556 / 2;
const isLeft = params.labelRect.x < 556 / 2; const points = params.labelLinePoints;
const points = params.labelLinePoints; // Update the end point.
// Update the end point. points[2][0] = isLeft
points[2][0] = isLeft ? params.labelRect.x
? params.labelRect.x : params.labelRect.x + params.labelRect.width;
: params.labelRect.x + params.labelRect.width; return {
return { labelLinePoints: points
labelLinePoints: points };
}; },
}, data: data
data: data }]
}]
} }
return option return option
} }
......
...@@ -154,8 +154,8 @@ ...@@ -154,8 +154,8 @@
<div class="box3-main-left" id="box3Chart"></div> <div class="box3-main-left" id="box3Chart"></div>
<div class="box3-main-right"> <div class="box3-main-right">
<div class="box3-right-item" v-for="(item, index) in box3RightData" :key="index"> <div class="box3-right-item" v-for="(item, index) in box3RightData" :key="index">
<div class="icon"> <div class="icon" @click="handleClickPerson">
<img :src="item.imageUrl" alt="" /> <img :src="item.imageUrl?item.imageUrl:DefaultIcon1" alt="" />
</div> </div>
<div class="info"> <div class="info">
<div class="info-header"> <div class="info-header">
...@@ -188,6 +188,8 @@ import { ...@@ -188,6 +188,8 @@ import {
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import DefaultIcon1 from '@/assets/icons/default-icon1.png'
const router = useRouter(); const router = useRouter();
import InfoImg from "./images/img.png"; import InfoImg from "./images/img.png";
import Icon1 from "./images/icon1.png"; import Icon1 from "./images/icon1.png";
...@@ -477,6 +479,17 @@ const handleGetThinkPerson = async () => { ...@@ -477,6 +479,17 @@ const handleGetThinkPerson = async () => {
} }
}; };
// 点击人物头像,跳转到人物主页
const handleClickPerson = () => {
const route = router.resolve({
path: "/characterPage",
query: {
type: 3 // 1 2 3
}
});
window.open(route.href, "_blank");
};
onMounted(() => { onMounted(() => {
handleGetThinkTankInfoBasic() handleGetThinkTankInfoBasic()
handleGetThinkTankInfoBranch() handleGetThinkTankInfoBranch()
...@@ -788,9 +801,9 @@ onMounted(() => { ...@@ -788,9 +801,9 @@ onMounted(() => {
.box1-main-right { .box1-main-right {
margin-left: 38px; margin-left: 38px;
margin-top: 26px; margin-top: 6px;
width: 800px; width: 800px;
height: 270px; height: 300px;
} }
} }
...@@ -950,6 +963,7 @@ onMounted(() => { ...@@ -950,6 +963,7 @@ onMounted(() => {
width: 48px; width: 48px;
height: 48px; height: 48px;
margin-left: 8px; margin-left: 8px;
cursor: pointer;
img { img {
width: 100%; width: 100%;
......
...@@ -3,7 +3,7 @@ const getPieChart = (data) => { ...@@ -3,7 +3,7 @@ const getPieChart = (data) => {
series: [ series: [
{ {
type: 'pie', type: 'pie',
radius: [70, 100], radius: [80, 110],
height: '100%', height: '100%',
left: 'center', left: 'center',
width: '100%', width: '100%',
...@@ -13,7 +13,13 @@ const getPieChart = (data) => { ...@@ -13,7 +13,13 @@ const getPieChart = (data) => {
}, },
label: { label: {
alignTo: 'edge', alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 个 {d}%}', // formatter: '{name|{b}}\n{time|{c} 个 {d}%}',
formatter: function (params) {
console.log(params, 'params')
// params.c 是当前数据项的 value 值
const time = params.data.value / 1000000; // 将值除以 1000000
return `{name|${params.data.name}}\n{time|${time.toFixed(2)}}亿美元`; // 使用 toFixed(2) 保留两位小数
},
minMargin: 15, minMargin: 15,
edgeDistance: 10, edgeDistance: 10,
lineHeight: 15, lineHeight: 15,
...@@ -22,10 +28,12 @@ const getPieChart = (data) => { ...@@ -22,10 +28,12 @@ const getPieChart = (data) => {
fontSize: 16, fontSize: 16,
color: 'rgba(59, 65, 75, 1)', color: 'rgba(59, 65, 75, 1)',
fontWeight: 700, fontWeight: 700,
lineHeight: 20
}, },
time: { time: {
fontSize: 14, fontSize: 14,
color: 'rgba(59, 65, 75, 1)', color: 'rgba(59, 65, 75, 1)',
lineHeight: 20
} }
} }
}, },
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
<div class="title-right">{{ item.country }}</div> <div class="title-right">{{ item.country }}</div>
</div> </div>
<el-popover effect="dark" trigger="click" :content="item.desc" placement="top-start"> <el-popover effect="dark" :content="item.desc" placement="top-start">
<template #reference> <template #reference>
<div class="content">{{ item.desc }}</div> <div class="content">{{ item.desc }}</div>
</template> </template>
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
<div class="title">{{ "智库发布" }}</div> <div class="title">{{ "智库发布" }}</div>
</div> </div>
<div class="box1-header-right"> <div class="box1-header-right" @click="toDetaile()">
查看详情 > 查看详情 >
</div> </div>
</div> </div>
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
<div class="title">{{ box1Data[box1DataIndex]?.reportName }}</div> <div class="title">{{ box1Data[box1DataIndex]?.reportName }}</div>
<div class="tag-box"> <div class="tag-box">
<div class="tag" v-for="(item, index) in box1Data[box1DataIndex]?.industryVOList" :key="index"> <div class="tag" v-for="(item, index) in box1Data[box1DataIndex]?.industryVOList" :key="index">
{{ item }} {{ item.industryName }}
</div> </div>
</div> </div>
<div class="content">{{ box1Data[box1DataIndex]?.summary }}</div> <div class="content">{{ box1Data[box1DataIndex]?.summary }}</div>
...@@ -139,6 +139,7 @@ ...@@ -139,6 +139,7 @@
<div class="logo"> <div class="logo">
<img :src="box1Data[box1DataIndex]?.thinkTankImage" alt="" /> <img :src="box1Data[box1DataIndex]?.thinkTankImage" alt="" />
</div> </div>
<div class="text">{{ box1Data[box1DataIndex]?.thinkTankName }}</div>
<div class="text">{{ box1Data[box1DataIndex]?.reportDate }}</div> <div class="text">{{ box1Data[box1DataIndex]?.reportDate }}</div>
</div> </div>
</div> </div>
...@@ -168,9 +169,14 @@ ...@@ -168,9 +169,14 @@
{{ item.status || "一般风险" }} {{ item.status || "一般风险" }}
</div> </div>
<div class="item-right"> <div class="item-right">
<div class="text"> <el-popover effect="dark" :width="500" :content="item.title" placement="top-start">
{{ item.title }} <template #reference>
</div> <div class="text">
{{ item.title }}
</div>
</template>
</el-popover>
<div class="time">{{ item.time }}</div> <div class="time">{{ item.time }}</div>
</div> </div>
</div> </div>
...@@ -196,7 +202,7 @@ ...@@ -196,7 +202,7 @@
</div> </div>
</div> </div>
<div class="box3-main"> <div class="box3-main">
<div class="box3-item" v-for="(news, index) in newsList" :key="index"> <div class="box3-item" v-for="(news, index) in newsList" :key="index" @click="handleToNewsAnalysis(news)">
<div class="left"> <div class="left">
<img :src="news.newsImage !== null ? news.newsImage : defaultNewsIcon" /> <img :src="news.newsImage !== null ? news.newsImage : defaultNewsIcon" />
</div> </div>
...@@ -205,7 +211,13 @@ ...@@ -205,7 +211,13 @@
<div class="title">{{ news.newsTitle }}</div> <div class="title">{{ news.newsTitle }}</div>
<div class="time">{{ news.newsOrg }}</div> <div class="time">{{ news.newsOrg }}</div>
</div> </div>
<div class="right-footer">{{ news.newsContent }}</div>
<el-popover effect="dark" :width=700 :content="news.newsContent" placement="top-start">
<template #reference>
<div class="right-footer">{{ news.newsContent }}</div>
</template>
</el-popover>
</div> </div>
</div> </div>
</div> </div>
...@@ -231,7 +243,7 @@ ...@@ -231,7 +243,7 @@
</div> --> </div> -->
<div class="box4-main"> <div class="box4-main">
<div class="box4-main-item" v-for="(item, index) in messageList" :key="index"> <div class="box4-main-item" v-for="(item, index) in messageList" :key="index">
<div class="left"> <div class="left" @click="handleClickPerson(item)">
<img :src="item.personImage ? item.personImage : defaultHeaderIcin" alt="" /> <img :src="item.personImage ? item.personImage : defaultHeaderIcin" alt="" />
</div> </div>
<div class="right"> <div class="right">
...@@ -314,11 +326,16 @@ ...@@ -314,11 +326,16 @@
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }"> :class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }">
{{ index + 1 }} {{ index + 1 }}
</div> </div>
<div class="item-center" <!-- <el-popover effect="dark" :content="item.clause" placement="top-start">
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }"> <template #reference> -->
{{ item.clause }} <div class="item-center"
</div> :class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }">
<div class="item-right">{{ `${item.count}份报告 >` }}</div> {{ item.clause }}
</div>
<!-- </template>
</el-popover> -->
<!-- <div class="item-right">{{ `${item.count}份报告 >` }}</div> -->
</div> </div>
</div> </div>
</div> </div>
...@@ -388,9 +405,14 @@ ...@@ -388,9 +405,14 @@
<div class="footer-card-top"> <div class="footer-card-top">
<img :src="item.imageUrl" alt="" /> <img :src="item.imageUrl" alt="" />
</div> </div>
<div class="footer-card-title"> <el-popover effect="dark" :content="item.name" placement="top-start">
{{ item.name }} <template #reference>
</div> <div class="footer-card-title">
{{ item.name }}
</div>
</template>
</el-popover>
<div class="footer-card-footer"> <div class="footer-card-footer">
<div class="time">{{ item.times }}</div> <div class="time">{{ item.times }}</div>
<div class="from">{{ item.thinkTankName }}</div> <div class="from">{{ item.thinkTankName }}</div>
...@@ -431,6 +453,7 @@ import { ...@@ -431,6 +453,7 @@ import {
getThinkTankReportNews, getThinkTankReportNews,
getThinkTankReportRemarks getThinkTankReportRemarks
} from "@/api/thinkTank/overview"; } from "@/api/thinkTank/overview";
import { getPersonSummaryInfo } from "@/api/common/index";
import getMultiLineChart from "./utils/multiLineChart"; import getMultiLineChart from "./utils/multiLineChart";
import getPieChart from "./utils/piechart"; import getPieChart from "./utils/piechart";
...@@ -567,6 +590,17 @@ function changeBox1Data(type) { ...@@ -567,6 +590,17 @@ function changeBox1Data(type) {
box1DataIndex.value === box1Data.value.length - 1 ? "" : (box1DataIndex.value = box1DataIndex.value + 1); box1DataIndex.value === box1Data.value.length - 1 ? "" : (box1DataIndex.value = box1DataIndex.value + 1);
} }
} }
const toDetaile = () => {
const route = router.resolve({
name: "ReportDetail",
params: {
id: box1Data.value[box1DataIndex.value].reportId
}
});
window.open(route.href, "_blank");
}
// 风险信号 // 风险信号
const warningList = ref([ const warningList = ref([
{ {
...@@ -977,78 +1011,80 @@ const box7Data = ref({ ...@@ -977,78 +1011,80 @@ const box7Data = ref({
{ source: "美国国务院", target: "兰德公司", value: 15 } { source: "美国国务院", target: "兰德公司", value: 15 }
] ]
}); });
function transformThinkTankData(data) {
// 遍历每个智库
function transformDataToSankey(inputData) {
const nodes = []; const nodes = [];
const links = []; const links = [];
const nodeSet = new Set(); // 用于去重
// 遍历每个智库 // 遍历输入数据
data.forEach(thinkTank => { inputData.forEach(item => {
const thinkTankName = thinkTank.thinkTankName; const thinkTankName = item.thinkTankName;
// 添加智库节点 // 添加智库节点(如果尚未添加)
if (!nodeSet.has(thinkTankName)) { if (!nodes.some(node => node.name === thinkTankName)) {
nodes.push({ name: thinkTankName }); nodes.push({ name: thinkTankName });
nodeSet.add(thinkTankName);
} }
// 遍历每个资金来源 // 遍历捐赠来源
thinkTank.thinkTankDonationSourceVOList.forEach(source => { item.thinkTankDonationSourceVOList.forEach(donation => {
const { amount, institution, secondInstitution } = source; const institution = donation.institution;
const secondInstitution = donation.secondInstitution;
const amount = donation.amount;
// 处理机构节点 // 添加捐赠机构节点(如果尚未添加)
if (institution && !nodeSet.has(institution)) { if (!nodes.some(node => node.name === institution)) {
nodes.push({ name: institution }); nodes.push({ name: institution });
nodeSet.add(institution);
} }
// 处理二级机构节点 // 如果存在二级机构,也添加二级机构节点(如果尚未添加)
if (secondInstitution && !nodeSet.has(secondInstitution)) { if (secondInstitution && !nodes.some(node => node.name === secondInstitution)) {
nodes.push({ name: secondInstitution }); nodes.push({ name: secondInstitution });
nodeSet.add(secondInstitution);
} }
// 构建链接 // 添加链接
if (institution && secondInstitution) { if (secondInstitution) {
// 情况1: institution → secondInstitution → thinkTankName // 如果存在二级机构,先从捐赠机构到二级机构
links.push({ if (institution !== secondInstitution) { // 检查自引用
source: institution, links.push({
target: secondInstitution, source: institution,
value: amount target: secondInstitution,
}); value: amount
});
links.push({ }
source: secondInstitution, // 再从二级机构到智库
target: thinkTankName, if (secondInstitution !== thinkTankName) { // 检查自引用
value: amount links.push({
}); source: secondInstitution,
} else if (institution && !secondInstitution) { target: thinkTankName,
// 情况2: institution → thinkTankName value: amount
links.push({ });
source: institution, }
target: thinkTankName, } else {
value: amount // 如果没有二级机构,直接从捐赠机构到智库
}); if (institution !== thinkTankName) { // 检查自引用
} else if (!institution && !secondInstitution) { links.push({
// 情况3: 只有智库节点 source: institution,
links.push({ target: thinkTankName,
source: thinkTankName, value: amount
value: amount });
}); }
} }
}); });
}); });
console.log(nodes, links, 'nodes, linksnodes, links')
return { nodes, links }; return { nodes, links };
} }
// 智库资金流向 // 智库资金流向
const handleGetThinkTankDonation = async () => { const handleGetThinkTankDonation = async () => {
try { try {
const res = await getThinkTankDonation(); const res = await getThinkTankDonation();
console.log("智库资金流向", res); console.log("智库资金流向", res.data, transformDataToSankey(res.data));
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
box7Data.value = transformThinkTankData(res.data); box7Data.value = transformDataToSankey(res.data);
} }
} catch (error) { } catch (error) {
console.error("获取智库资金流向error", error); console.error("获取智库资金流向error", error);
...@@ -1386,6 +1422,79 @@ const handleToMoreRiskSignal = () => { ...@@ -1386,6 +1422,79 @@ const handleToMoreRiskSignal = () => {
window.open(route.href, "_blank"); window.open(route.href, "_blank");
}; };
// 查看更多新闻资讯
const handleToMoreNews = () => {
const route = router.resolve("/newsBrief");
window.open(route.href, "_blank");
};
// 点击人物头像,跳转到人物主页
const handleClickPerson = async item => {
console.log("person", item);
const personTypeList = JSON.parse(window.sessionStorage.getItem("personTypeList"));
console.log("personTypeList", personTypeList);
let type = 0;
let personTypeName = "";
const params = {
personId: item.personId
};
try {
const res = await getPersonSummaryInfo(params);
console.log("人物全局信息", res);
if (res.code === 200 && res.data) {
const arr = personTypeList.filter(item => {
return item.typeId === res.data.personType;
});
console.log("arr", arr);
if (arr && arr.length > 0) {
personTypeName = arr[0].typeName;
console.log("personTypeName", personTypeName);
if (personTypeName === "科技企业领袖") {
type = 1;
} else if (personTypeName === "国会议员") {
type = 2;
} else if (personTypeName === "智库研究人员") {
type = 3;
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
return;
}
const route = router.resolve({
path: "/characterPage",
query: {
type: type, // type=1为科技企业领袖,2为国会议员,3为智库研究人员
personId: item.personId
}
});
window.open(route.href, "_blank");
} else {
personTypeName = "";
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} else {
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} catch (error) {}
};
// 点击新闻条目,跳转到新闻分析页
const handleToNewsAnalysis = news => {
const route = router.resolve({
path: "/newsAnalysis",
query: {
newsId: news.newsId
}
});
window.open(route.href, "_blank");
};
const handleToReportDetail = id => { const handleToReportDetail = id => {
const route = router.resolve({ const route = router.resolve({
name: "ReportDetail", name: "ReportDetail",
...@@ -2012,11 +2121,11 @@ onMounted(async () => { ...@@ -2012,11 +2121,11 @@ onMounted(async () => {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
gap: 6px; gap: 6px;
height: 36px;
.logo { .logo {
margin-top: 5px; width: 36px;
width: 16px; height: 36px;
height: 16px;
img { img {
width: 100%; width: 100%;
...@@ -2025,6 +2134,7 @@ onMounted(async () => { ...@@ -2025,6 +2134,7 @@ onMounted(async () => {
} }
.text { .text {
margin-top: 6px;
height: 24px; height: 24px;
color: rgba(95, 101, 108, 1); color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
...@@ -2176,6 +2286,7 @@ onMounted(async () => { ...@@ -2176,6 +2286,7 @@ onMounted(async () => {
} }
.time { .time {
width: 90px;
margin-left: 10px; margin-left: 10px;
line-height: 47px; line-height: 47px;
color: rgba(132, 136, 142, 1); color: rgba(132, 136, 142, 1);
...@@ -2357,6 +2468,7 @@ onMounted(async () => { ...@@ -2357,6 +2468,7 @@ onMounted(async () => {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
cursor: pointer;
} }
} }
} }
...@@ -2494,6 +2606,9 @@ onMounted(async () => { ...@@ -2494,6 +2606,9 @@ onMounted(async () => {
margin-top: 5px; margin-top: 5px;
width: 36px; width: 36px;
height: 36px; height: 36px;
border-radius: 18px;
overflow: hidden;
cursor: pointer;
img { img {
width: 100%; width: 100%;
...@@ -2837,7 +2952,7 @@ onMounted(async () => { ...@@ -2837,7 +2952,7 @@ onMounted(async () => {
.item-center { .item-center {
margin-left: 20px; margin-left: 20px;
width: 315px; width: 425px;
height: 24px; height: 24px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
......
<template>
<div class="wrap">
<div class="header">
<div class="header-top">
<div class="header-top-left">
<img :src="thinkInfo.contentUrl" alt="" />
<div>
<div class="title">{{ thinkInfo.name }}</div>
<div class="en-title">
{{ thinkInfo.ename }}
</div>
<div style="display: flex;">
<div class="tag-box" v-for="value in thinkInfo.tags">
<div class="tag">{{ value.industryName }}</div>
</div>
</div>
</div>
</div>
<div class="header-top-right">
<div class="name">{{ thinkInfo.thinkTankName }}</div>
<div class="time">{{ thinkInfo.times }}</div>
</div>
</div>
</div>
<div class="main">
<div class="main-header">
<div style=" margin-top: 17px;">
智库报告原文
</div>
</div>
<div class="report-box">
<iframe :src="reportUrl" width="50%" height="100%">
</iframe>
<iframe :src="reportUrlEn" width="50%" height="100%">
</iframe>
<!-- <pdf :pdfUrl="reportUrl" style="width: 48%;" />
<pdf :pdfUrl="reportUrlEn" style="width: 48%;" /> -->
<!-- <iframe src="https://www.rand.org/pubs/research_reports/RRA3572-1.html" width="100%" height="600px"
frameborder="0" allowfullscreen></iframe> -->
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
import pdf from "./pdf.vue";
import {
getThinkTankReportSummary,
getThinkTankReportcontentUrl
} from "@/api/thinkTank/overview";
import { useRouter } from "vue-router";
const router = useRouter();
const reportUrl = ref('')
const reportUrlEn = ref('')
const thinkInfo = ref({})
// 获取报告全局信息
const handleGetThinkTankReportSummary = async () => {
try {
const res = await getThinkTankReportSummary(router.currentRoute._value.params.id);
console.log("报告全局信息", res);
if (res.code === 200 && res.data) {
thinkInfo.value = res.data
}
} catch (error) {
console.error("获取报告全局信息error", error);
}
};
//获取原文
const handleGetThinkTankReportcontentUrl = async () => {
try {
const res = await getThinkTankReportcontentUrl(router.currentRoute._value.params.id);
console.log("获取原文", res);
if (res.code === 200 && res.data) {
reportUrl.value = res.data.content
reportUrlEn.value = res.data.contentEn
}
} catch (error) {
console.error("获取原文error", error);
}
};
const tabActiveName = ref("报告分析");
const switchTab = name => {
tabActiveName.value = name;
};
onMounted(async () => {
handleGetThinkTankReportSummary()
handleGetThinkTankReportcontentUrl()
});
</script>
<style lang="scss" scoped>
.wrap {
width: 1920px;
// height: 984px;
.header {
width: 1920px;
box-sizing: border-box;
border-bottom: 1px solid rgba(234, 236, 238, 1);
border-top: 1px solid rgba(234, 236, 238, 1);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
background: rgba(255, 255, 255, 1);
.header-top {
margin-top: 20px;
margin-left: 160px;
margin-bottom: 20px;
display: flex;
justify-content: space-between;
margin-right: 160px;
.header-top-left {
display: flex;
img {
width: 72px;
height: 88px;
}
.title {
margin-left: 20px;
height: 26px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 0px;
text-align: left;
}
.en-title {
margin-left: 20px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
.tag-box {
margin-top: 11px;
display: flex;
gap: 8px;
margin-left: 20px;
.tag {
height: 26px;
padding: 0 8px;
box-sizing: border-box;
border: 1px solid rgba(231, 243, 255, 1);
border-radius: 4px;
background: rgba(246, 250, 255, 1);
color: var(--color-main-active);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: left;
}
}
}
.header-top-right {
.name {
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: right;
}
.time {
height: 24px;
margin-top: 5px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0px;
text-align: right;
}
}
}
.header-bottom {
margin: 0 auto;
margin-top: 30px;
width: 1600px;
height: 48px;
display: flex;
justify-content: space-between;
.tab-box {
width: 224px;
height: 48px;
display: flex;
gap: 24px;
.tab {
width: 94px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
cursor: pointer;
border-bottom: 2px solid transparent;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 18px;
font-weight: 400;
line-height: 24px;
}
.textActive {
color: rgba(5, 95, 194, 1);
font-weight: 700;
}
}
.tabActive {
border-bottom: 2px solid rgba(5, 95, 194, 1);
}
}
.btn-box {
display: flex;
gap: 12px;
.btn {
width: 120px;
height: 36px;
box-sizing: border-box;
border: 1px solid rgba(230, 231, 232, 1);
border-radius: 6px;
background: rgba(255, 255, 255, 1);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
width: 66px;
height: 22px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 22px;
letter-spacing: 0px;
text-align: center;
}
}
.btn1 {
border-radius: 6px;
background: var(--color-main-active);
.text {
color: rgba(255, 255, 255, 1);
}
}
}
}
}
.main {
margin-left: 160px;
background: #ffffff;
width: 1600px;
height: 1025px;
overflow: hidden;
.main-header {
height: 64px;
/* box-sizing: border-box; */
border-bottom: 1px solid rgb(234, 236, 238);
border-top: 1px solid rgb(234, 236, 238);
/* box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); */
background: rgb(255, 255, 255);
margin: 0 70px;
color: rgba(59, 65, 75, 1);
line-height: 64px;
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 20px;
font-weight: 700;
line-height: 26px;
letter-spacing: 0px;
text-align: left;
}
.report-box {
width: 100%;
height: 750px;
overflow: auto;
display: flex;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="pdf-viewer">
<canvas ref="pdfCanvas"></canvas>
<div v-if="loading" class="loading">加载中...</div>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
import * as pdfjsLib from 'pdfjs-dist';
pdfjsLib.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url
).href;
export default {
name: 'PdfViewer',
props: {
pdfUrl: {
type: String,
required: true
}
},
setup(props) {
const pdfCanvas = ref(null);
const loading = ref(true);
onMounted(async () => {
try {
const loadingTask = pdfjsLib.getDocument(props.pdfUrl);
const pdf = await loadingTask.promise;
const page = await pdf.getPage(1); // 加载第一页
const viewport = page.getViewport({ scale: 1.5 });
const context = pdfCanvas.value.getContext('2d');
const renderContext = {
canvasContext: context,
viewport: viewport
};
pdfCanvas.value.width = viewport.width;
pdfCanvas.value.height = viewport.height;
await page.render(renderContext).promise;
} catch (error) {
console.error('加载 PDF 出错:', error);
} finally {
loading.value = false;
}
});
return {
pdfCanvas,
loading
};
}
};
</script>
<style scoped>
.pdf-viewer {
position: relative;
width: 100%;
height: 800px;
}
canvas {
width: 100%;
height: 100%;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 18px;
color: #333;
}
</style>
\ No newline at end of file
...@@ -16,12 +16,19 @@ const getPieChart = (data) => { ...@@ -16,12 +16,19 @@ const getPieChart = (data) => {
formatter: '{name|{b}}\n{time|{c} 条 {d}%}', formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
minMargin: 5, minMargin: 5,
edgeDistance: 10, edgeDistance: 10,
lineHeight: 15, lineHeight: 24,
rich: { rich: {
time: { name: {
fontSize: 10, fontSize: 16,
color: '#999' color: 'rgba(59, 65, 75, 1)',
} fontFamily: 'Microsoft YaHei',
fontWeight: 700
},
time: {
fontSize: 16,
color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei',
}
} }
}, },
labelLine: { labelLine: {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论