提交 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 @@
"json5": "^2.2.3",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",
"pdfjs-dist": "^5.4.449",
"vue": "^3.4.0",
"vue-router": "^4.2.5"
},
......@@ -664,6 +665,244 @@
"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": {
"version": "2.1.5",
"resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
......@@ -5164,6 +5403,17 @@
"dev": true,
"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": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
......
......@@ -34,6 +34,7 @@
"json5": "^2.2.3",
"lodash": "^4.17.21",
"markdown-it": "^14.1.0",
"pdfjs-dist": "^5.4.449",
"vue": "^3.4.0",
"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 @@
</div>
<div class="brand-text" @click="handleToHome">
<div class="text-ch">某方向风险监测预警系统</div>
<!-- <div class="text-en">
National Science and Technology Security Risk Monitoring and Early Warning System
</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="email">
<img src="@/assets/icons/header-icon.png" alt="" />
......@@ -73,9 +23,6 @@
</nav>
</el-header>
<!-- 面包屑导航 -->
<!-- <Breadcrumb /> -->
<el-main class="main-container">
<router-view />
</el-main>
......@@ -85,6 +32,7 @@
</div>
<div class="text">智能问答</div>
</div>
<div class="ai-dialog" v-if="isShowAiBox">
<AiBox @close="closeAiBox" />
</div>
......@@ -93,14 +41,31 @@
</template>
<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 { useRouter } from "vue-router";
import Breadcrumb from "@/components/BreadCrumb/index.vue";
import AiBox from "./components/AiBox.vue";
import {getPersonType} from '@/api/common/index'
// import { useDraggable } from "@vueuse/core";
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 = () => {
router.push({
path: "/overview"
......@@ -120,6 +85,30 @@ const openAiBox = () => {
const handleHomeCommand = 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>
<style>
......@@ -141,6 +130,7 @@ body {
}
.el-popover {
width: 100%;
font-family: "Microsoft YaHei";
color: rgba(95, 101, 108, 1);
font-style: Regular;
......@@ -150,6 +140,10 @@ body {
letter-spacing: 0px;
text-align: justify;
}
.el-popper[data-popper-placement^=top]>.el-popper__arrow:before {
display: none;
}
</style>
<style lang="scss" scoped>
......@@ -315,11 +309,17 @@ body {
.wrapper {
position: relative;
.target {
// position: absolute;
// bottom: 20%;
// right: 46px;
z-index: 9999;
}
.ai-btn {
position: absolute;
bottom: 20%;
right: 46px;
bottom: 240px;
right: 10px;
z-index: 9999;
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) {
}
// 政令涉及领域
export function getDecreeArea() {
export function getDecreeArea(params) {
return request({
method: 'GET',
url: `/api/administrativeOrderOverview/industry`,
url: `/api/administrativeOrderOverview/industry/${params.year}`,
params
})
}
......
......@@ -47,3 +47,14 @@ export function getDecreeSummary(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) {
// 最新动态
/**
* @param { orgId, cRelated, currentPage, pageSize }
* @param { orgId, cRelated,dynamicsType, currentPage, pageSize }
*/
export function getGovOrgLatestDynamics(params) {
return request({
......@@ -62,3 +62,83 @@ export function getGovOrgOpinions(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) => {
);
}
//获取报告原文
export const getThinkTankReportcontentUrl = (params) => {
return request(
{
method: 'GET',
url: `/api/thinkTankReport/contentUrl/${params}`,
}
);
}
//获取报告内容摘要
export function getThinkTankReportAbstract(params) {
return request({
......@@ -230,7 +240,7 @@ export function getThinkTankReportIndustry(params) {
export function getThinkTankReportIndustryCloud(params) {
return request({
method: 'GET',
url: `/api/thinkTankReport/industry/${params.id}/${params.industryId}`,
url: `/api/thinkTankReport/keyword/${params.id}`,
})
}
......
......@@ -2,7 +2,7 @@
import thinkTank from "@/views/thinkTank/index.vue";
import ThinkTankDetail from "@/views/thinkTank/ThinkTankDetail/index.vue";
import ReportDetail from "@/views/thinkTank/ReportDetail/index.vue";
import ReportOriginal from "@/views/thinkTank/reportOriginal/index.vue"
const thinktankRoutes = [
// 智库系统的主要路由
{
......@@ -29,6 +29,14 @@ const thinktankRoutes = [
title: "报告详情"
}
},
{
path: "/thinkTank/reportOriginal/:id",
name: "ReportOriginal",
component: ReportOriginal,
meta: {
title: "报告原文"
}
},
]
......
......@@ -32,3 +32,22 @@
--tag-btn3-text-color: rgba(82, 196, 26, 1);
}
.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 @@
</div>
<div class="right-footer">
<div class="footer-left">
{{ `共${total}项调查` }}
{{ `共 ${total} 条法案` }}
</div>
<div class="footer-right">
<el-pagination
......
......@@ -67,6 +67,48 @@
class="content ai-content"
v-html="renderMarkdown(message.content)"
></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 v-else class="user-item">
......@@ -175,17 +217,49 @@ const loadingDotIndex = ref(0);
// 消息数据
const messages = ref([
{
type: "user",
content: "你好"
},
{
type: "ai",
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`
],
content: `2025年9月实体清单的主要制裁实体、制裁原因\n\n 时间范围\n-当前查询的时间范围为:2025年9月16日。`
}
// {
// type: "user",
// content: "你好"
// },
// {
// type: "ai",
// 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`
// ],
// 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 渲染器
......@@ -419,6 +493,13 @@ const connectSSE = async question => {
aiMessage.value += content;
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") {
// ElMessage.success("问答完成!");
// abortController.value.abort();
......@@ -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) {
console.log(data.detail.error.message);
// ElMessage.error(data.detail.error.message);
......@@ -1144,6 +1233,78 @@ onUnmounted(() => {
padding: 1px 10px;
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 {
margin-top: 32px;
......
......@@ -256,7 +256,11 @@
<div class="title">{{ news.title }}</div>
<div class="time">{{ news.from }}</div>
</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>
......@@ -270,7 +274,7 @@
</div>
<div class="box4-main">
<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="" />
</div>
<div class="right">
......@@ -294,16 +298,12 @@
</div>
<div class="box5-header-title">{{ "行政令发布频度" }}</div>
</div>
</div>
<div class="box5-main">
<div class="box5-chart" id="chart1"></div>
<div class="box5-selectbox">
<el-select
@change="handleBox5YearChange"
v-model="box5SelectedYear"
placeholder="选择时间"
style="width: 80px"
style="width: 120px"
>
<el-option
v-for="item in box5YearList"
......@@ -314,6 +314,10 @@
</el-select>
</div>
</div>
<div class="box5-main">
<div class="box5-chart" id="chart1"></div>
</div>
</div>
<div class="box6">
<div class="box6-header">
......@@ -321,6 +325,21 @@
<img src="./assets/images/box4-header-icon.png" alt="" />
</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 class="box6-main" id="chart2"></div>
</div>
......@@ -334,7 +353,12 @@
<div class="header-title">{{ "关键行政令" }}</div>
</div>
<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">
<img src="./assets/images/warning.png" alt="" />
</div>
......@@ -343,7 +367,11 @@
<div class="title">{{ item.title }}</div>
<div class="time">{{ item.time }}</div>
</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>
......@@ -489,7 +517,7 @@
</div>
<div class="footer-box">
<div class="footer-left">
{{ `共${totalDecreesNum}项调查` }}
{{ `共 ${totalDecreesNum} 条政令` }}
</div>
<div class="footer-right">
<el-pagination
......@@ -524,6 +552,7 @@ import {
getDecreeOrderList,
getDecreehylyList
} from "@/api/decree/home";
import { getPersonSummaryInfo } from "@/api/common/index";
import { getNews, getSocialMedia } from "@/api/general/index";
import WordCloudMap from "./WordCloudMap.vue";
import DivideHeader from "@/components/DivideHeader.vue";
......@@ -571,6 +600,7 @@ import News5 from "./assets/images/news5.png";
import Message1 from "./assets/images/message-icon1.png";
import Message2 from "./assets/images/message-icon2.png";
import Message3 from "./assets/images/message-icon3.png";
import { ElMessage } from "element-plus";
// 跳转行政机构主页
const handleToInstitution = item => {
......@@ -610,13 +640,9 @@ const govInsList = ref([
// name: "美国财政部"
// },
]);
const checkedGovIns = ref(['白宫'])
const handleChangeCheckedGovIns = (val) => {
}
const checkedGovIns = ref(["白宫"]);
const handleChangeCheckedGovIns = val => {};
const handleGetDepartmentList = async () => {
try {
......@@ -719,26 +745,25 @@ const handleClickDecree = decree => {
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([
{
id: 1,
name: "关于对中华人民共和国合成阿片类药物供应链...",
postDate: "一天前",
riskLevel: "特别重大"
},
{
id: 2,
name: "关于调整钢铁进口的公告",
postDate: "一天前",
riskLevel: "重大风险"
},
{
id: 3,
name: "关于修订对中华人民共和国低价值进口商品适...",
postDate: "一天前",
riskLevel: "一般风险"
}
// {
// id: 1,
// name: "关于对中华人民共和国合成阿片类药物供应链...",
// postDate: "一天前",
// riskLevel: "特别重大"
// }
]);
const handlegetDecreeRiskSignal = async () => {
try {
......@@ -828,22 +853,70 @@ const handleGetMessage = async () => {
return {
img: item.personImage,
name: item.personName,
time: item.time + " · 发布于" + item.orgName,
content: item.remarks
time: item.time.replace("T", " ") + " · 发布于" + item.orgName,
content: item.remarks,
personId: item.personId,
remarksId: item.remarksId
};
});
} catch (error) {}
};
handleGetMessage();
// 点击人物头像,跳转到人物主页
const handleClickPerson = () => {
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: 3 // 1 2 3
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) {}
};
// 行政令发布频度
......@@ -919,9 +992,36 @@ const chart2Data = ref([
]);
// 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 params = {
year: box6SelectedYear.value
};
try {
const res = await getDecreeArea();
const res = await getDecreeArea(params);
console.log("政令涉及领域", res);
if (res.code === 200 && res.data) {
chart2Data.value = res.data.map(item => {
......@@ -941,6 +1041,10 @@ const handleBox6 = async () => {
setChart(chart2, "chart2");
};
const handleBox6YearChange = () => {
handleBox6();
};
// 关键行政令
const keyDecreeList = ref([
// {
......@@ -964,7 +1068,8 @@ const handleGetKeyDecree = async () => {
return {
title: item.name,
content: item.describe,
time: item.postDate
time: item.postDate,
id: item.orderId
};
});
}
......@@ -1012,7 +1117,6 @@ const handleSwithSort = () => {
isSort.value = !isSort.value;
};
const handleToPosi = id => {
// 0 618 1240 2350
switch (id) {
......@@ -1060,7 +1164,8 @@ const pubTime = ref([
{ id: "2023", name: "2023年" },
{ id: "2022", name: "2022年" },
{ id: "2021", name: "2021年" },
{ id: "更早时间", name: "更早时间" }
{ id: "2020", name: "2020年" },
// { id: "更早时间", name: "更早时间" }
]);
const activePubTime = ref(["2025"]);
......@@ -1088,7 +1193,7 @@ const decreeList = ref([
]);
const handleGetDecreeOrderList = async () => {
const p0 = checkedGovIns.value.join(',')
const p0 = checkedGovIns.value.join(",");
const p1 = activeAreaList.value.join(",");
const p2 = activePubTime.value.join(",");
const params = {
......@@ -1109,7 +1214,7 @@ const handleGetDecreeOrderList = async () => {
id: item.id,
time: item.postDate,
title: item.name,
desc: item.order,
desc: item.describe,
img: item.orgImage,
tagList: item.industryList
};
......@@ -1157,8 +1262,7 @@ watch(
val => {
handleGetDecreeOrderList();
}
)
);
// 切换当前政令
const handleSwithCurDecree = name => {
......@@ -2555,26 +2659,13 @@ onMounted(async () => {
line-height: 26px;
}
}
.box5-header-right {
width: 49px;
height: 24px;
margin-top: 12px;
margin-right: 27px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
.box5-selectbox {
margin-right: 20px;
margin-top: 8px;
}
}
.box5-main {
height: 397px;
position: relative;
.box5-selectbox {
position: absolute;
right: 10px;
top: 10px;
}
.box5-chart {
height: 397px;
}
......@@ -2613,17 +2704,10 @@ onMounted(async () => {
font-weight: 700;
line-height: 26px;
}
.header-right {
.box6-selectbox {
position: absolute;
right: 27px;
width: 49px;
height: 24px;
top: 12px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
right: 20px;
top: 8px;
}
}
.box6-main {
......@@ -2680,6 +2764,10 @@ onMounted(async () => {
margin-top: 16px;
margin-left: 25px;
display: flex;
cursor: pointer;
&:hover {
background: var(--color-bg-hover);
}
.icon {
margin-top: 6px;
width: 24px;
......@@ -2778,7 +2866,8 @@ onMounted(async () => {
}
.home-main-footer {
margin-top: 34px;
height: 1860px;
max-height: 1860px;
padding-bottom: 160px;
background: rgba(248, 249, 250, 1);
overflow: hidden;
.divide4 {
......@@ -2924,7 +3013,7 @@ onMounted(async () => {
}
.right {
width: 1284px;
height: 1489px;
max-height: 1489px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
box-sizing: border-box;
......@@ -2955,7 +3044,7 @@ onMounted(async () => {
}
}
.content-box {
height: 1367px;
max-height: 1367px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
overflow: hidden;
.main-item {
......@@ -3076,9 +3165,8 @@ onMounted(async () => {
}
}
.footer-box {
margin: 0 30px;
margin: 20px 30px;
height: 32px;
margin-top: 20px;
display: flex;
justify-content: space-between;
.footer-left {
......
......@@ -72,7 +72,7 @@
<div class="title">{{ "政令主要内容" }}</div>
</div>
<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="title">{{ val.content }}</div>
<div class="open">
......@@ -105,7 +105,7 @@
<script setup>
import { ref, computed, onMounted } from "vue";
import { useRoute } from "vue-router";
import router from "@/router";
import { getDecreeMainContent } from "@/api/decree/introduction";
import { getDecreeRelateOrder } from "@/api/decree/deepdig";
......@@ -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(() => {
handleGetRelateOrder();
});
......@@ -385,17 +395,17 @@ onMounted(() => {
background: rgba(246, 250, 255, 1);
display: flex;
.info-left {
width: 97px;
width: 242px;
height: 136px;
margin-top: 25px;
margin-left: 28px;
img {
width: 100%;
height: 100%;
// height: 100%;
}
}
.info-right {
margin-left: 35px;
margin-left: 20px;
margin-top: 22px;
.info-item {
display: flex;
......@@ -412,7 +422,7 @@ onMounted(() => {
line-height: 24px;
}
.item-right {
width: 899px;
width: 769px;
height: 30px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
......@@ -483,6 +493,10 @@ onMounted(() => {
background: rgba(255, 255, 255, 1);
border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex;
cursor: pointer;
&:hover{
background: var(--color-bg-hover);
}
.id {
width: 24px;
height: 24px;
......
......@@ -46,7 +46,7 @@
<!-- <el-button type="plain" size="large" icon="Search" @click="handleSwitchActiveName('法案原文')"
>政令原文</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>
</div>
</div>
......@@ -106,17 +106,24 @@
</div>
</div>
</div>
<!-- <div class="tool-box">
<div class="tool1">
<img src="./assets/icons/tool-icon1.png" alt="" />
<div class="report" v-if="isShowReport">
<div class="report-close" @click="handleCloseReport">
<img src="@/assets/icons/close.png" alt="" />
</div>
<div class="report-header">
{{ "政令原文" }}
</div>
<div class="report-main">
<div class="left">
<div v-if="!reportUrl" class="noContent">{{ "中文原文暂无数据" }}</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 class="tool2">
<img src="./assets/icons/tool-icon2.png" alt="" />
</div>
<div class="tool3">
<img src="./assets/icons/tool-icon3.png" alt="" />
</div>
</div> -->
</div>
</template>
......@@ -125,6 +132,7 @@ import { ref, onMounted, onUnmounted } from "vue";
import router from "@/router";
import { useRoute } from "vue-router";
import { getDecreeSummary } from "@/api/decree/introduction";
import { getDecreeReport } from "@/api/decree/introduction";
import search from "./assets/images/search.png";
import icon1 from "./assets/icons/icon1.png";
......@@ -134,12 +142,16 @@ import icon2Active from "./assets/icons/icon2_active.png";
import icon3 from "./assets/icons/icon3.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 decreeId = ref(route.query.id);
const isShowReport = ref(false);
const reportUrl = ref("");
const reportUrlEn = ref("");
const activeName = ref("分析报告");
const summaryInfo = ref({});
......@@ -186,7 +198,6 @@ const activeTitle = ref("政令概况");
const handleClickMainHeaderBtn = item => {
activeTitle.value = item.name;
window.sessionStorage.setItem("activeTitle", item.name);
router.push({
path: item.path,
query: {
......@@ -209,26 +220,119 @@ const handleGetSummary = async () => {
} 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(() => {
handleGetSummary();
if (window.sessionStorage.getItem("activeTitle")) {
activeTitle.value = window.sessionStorage.getItem("activeTitle");
}
console.log(route.path);
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>
<style lang="scss" scoped>
.layout-container {
width: 1920px;
height: 1016px;
width: 100vw;
height: 100vh;
min-width: 1920px;
min-height: 1016px;
background: rgba(249, 250, 252, 1);
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 {
width: 100%;
height: 100%;
......@@ -247,7 +351,7 @@ onUnmounted(() => {
.icon {
width: 64px;
height: 64px;
img{
img {
width: 100%;
height: 100%;
}
......
......@@ -163,22 +163,22 @@ const handleScroll = () => {
};
onMounted(async () => {
try {
const chainFishboneData = await getChainFishbone(props.chainId);
fishboneData.value = chainFishboneData?.causes ?? [];
// 等待DOM更新后检查是否需要滚动
nextTick(() => {
if (scrollContainerRef.value && fishboneRef.value) {
showScrollIndicator.value = fishboneRef.value.scrollWidth > scrollContainerRef.value.clientWidth;
updateScrollState();
}
});
console.log("鱼骨图数据:", fishboneData.value);
} catch (error) {
console.log(error);
}
// try {
// const chainFishboneData = await getChainFishbone(props.chainId);
// fishboneData.value = chainFishboneData?.causes ?? [];
// // 等待DOM更新后检查是否需要滚动
// nextTick(() => {
// if (scrollContainerRef.value && fishboneRef.value) {
// showScrollIndicator.value = fishboneRef.value.scrollWidth > scrollContainerRef.value.clientWidth;
// updateScrollState();
// }
// });
// console.log("鱼骨图数据:", fishboneData.value);
// } catch (error) {
// console.log(error);
// }
});
// 监听props中的chainId变化
......
......@@ -87,7 +87,7 @@
</div>
</div>
<div class="box2-main-main">
<Fishbone :chainId="2" />
<Fishbone :chainId="chainId" />
</div>
<div class="box2-main-footer">
<div class="box2-main-footer-left">
......@@ -95,7 +95,13 @@
<div class="icon">
<img src="@/assets/icons/warning.png" alt="" />
</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 class="bottom">{{ "基础支撑" }}</div>
</div>
......@@ -104,7 +110,15 @@
<div class="icon">
<img src="@/assets/icons/warning.png" alt="" />
</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 class="bottom">{{ "软件算法" }}</div>
</div>
......@@ -113,7 +127,15 @@
<div class="icon">
<img src="@/assets/icons/warning.png" alt="" />
</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 class="bottom">{{ "行业应用" }}</div>
</div>
......@@ -132,6 +154,7 @@ import router from "@/router";
import setChart from "@/utils/setChart";
import getBarChart from "./utils/barChart";
import { getDecreeIndustry, getDecreehylyList, getDecreeCompany, getDecreeAction } from "@/api/decree/influence";
import { getCnEntityOnChain, getChainFishbone, getChainInfoByDomainId, getChainStructure } from "@/api/exportControl";
const route = useRoute();
......@@ -195,6 +218,8 @@ const handleClickBox1Btn = btn => {
box1BtnActiveName.value = btn.name;
curAreaId.value = btn.id;
handleGetCompanyListByArea();
handleGetCompanyListByArea();
handleGetChainId();
};
// 获取行业领域列表
......@@ -207,6 +232,7 @@ const handleGetHylyList = async () => {
box1BtnActiveName.value = box1BtnList.value[0].name;
curAreaId.value = box1BtnList.value[0].id;
handleGetCompanyListByArea();
handleGetChainId();
}
} catch (error) {}
};
......@@ -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(() => {
handleGetChart1Data();
handleGetHylyList();
handleGetAction();
// handleGetAction();
handelBox1();
});
</script>
......@@ -372,8 +444,9 @@ onMounted(() => {
<style lang="scss" scoped>
.wrapper {
width: 100%;
height: 879px;
height: 100%;
display: flex;
justify-content: center;
.box-header {
display: flex;
height: 48px;
......
<template>
<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="box1">
<div class="box-header">
......@@ -29,13 +36,13 @@
<div class="box1-item" v-for="(item, index) in backgroundList" :key="index">
<div class="id">{{ index + 1 }}</div>
<div class="title">{{ item.content }}</div>
<div class="open">
<!-- <div class="open">
<img src="./assets/images/open-icon.png" alt="" />
</div>
</div> -->
</div>
</div>
<div class="box1-footer">
<div class="box1-footer-left">{{ `共计${backgroundListNum}指令` }}</div>
<div class="box1-footer-left">{{ `共计${backgroundListNum}背景` }}</div>
<div class="box1-footer-right">
<el-pagination :page-size="5" background layout="prev, pager, next" :total="backgroundListNum" />
</div>
......@@ -61,7 +68,13 @@
</div>
<div class="item-center">
<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 class="item-right">{{ item.time }}</div>
</div>
......@@ -87,11 +100,11 @@
</div>
</div>
<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="item-header">
<div class="name">{{ item.name }}</div>
<div class="info">{{ item.info }}</div>
<div class="name">{{ item.title }}</div>
<!-- <div class="info">{{ item.info }}</div> -->
</div>
<div class="item-content">{{ item.content }}</div>
</div>
......@@ -104,6 +117,7 @@
<script setup>
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import router from "@/router";
import { getDecreeBackground, getDecreeRelatedEvent, getDecreeDepend } from "@/api/decree/background";
import Img1 from "./assets/images/box2-img1.png";
......@@ -112,11 +126,16 @@ import Img3 from "./assets/images/box2-img3.png";
import Img4 from "./assets/images/box2-img4.png";
import Img5 from "./assets/images/box2-img5.png";
import { reduce } from "lodash";
import Index from "../index.vue";
const route = useRoute();
const decreeId = ref(route.query.id);
// 基本鼠标位置
const mouseX = ref(0);
const mouseY = ref(0);
// 提出背景
const box1BtnList = ref(["涉华背景", "全部背景"]);
const box1ActiveBtn = ref("涉华背景");
......@@ -144,8 +163,8 @@ const handleGetBackground = async () => {
const res = await getDecreeBackground(params);
console.log("提出背景", res);
if (res.code === 200 && res.data) {
backgroundListNum.value = res.data.numberOfElements
backgroundList.value = res.data.content
backgroundListNum.value = res.data.numberOfElements;
backgroundList.value = res.data.content;
} else {
backgroundListNum.value = 0;
backgroundList.value = [];
......@@ -162,75 +181,87 @@ const relatedEvents = ref([
// "斯坦福大学《2025年人工智能指数报告》显示,中美顶尖AI模型在MMLU(大规模多任务语言理解)等主流基准测试中的性能...",
// time: "2025-08-30"
// }
]);
const handleGetRelateEvents = async () => {
const params = {
id: decreeId.value
}
};
try {
const res = await getDecreeRelatedEvent(params)
console.log('相关事件', res);
if(res.code === 200 && res.data) {
relatedEvents.value = res.data.map( item => {
const res = await getDecreeRelatedEvent(params);
console.log("相关事件", res);
if (res.code === 200 && res.data) {
relatedEvents.value = res.data.map(item => {
return {
image: '',
image: item.imageUrl,
title: item.sjbt,
content: item.sjnr,
time: item.sjsj
}
})
};
});
} else {
relatedEvents.value = []
relatedEvents.value = [];
}
} catch (error) {
}
}
} catch (error) {}
};
// 法律依据
const laws = ref([
// {
// name: "《美国法典》",
// info: "第3编第301条",
// content:
// "允许总统通过行政命令(Executive Order)​​ 或其它书面形式授权行政部门或机构的负责人​(如国务卿、财政部长等)代行本属于总统的法定职能(由国会立法授予总统的职能)。"
// },
// {
// name: "《出口管制改革法案》",
// info: "",
// content:
// "该法案授权政府出于国家安全和外交政策目的对特定技术、商品和软件的出口进行管制。确保AI技术不流向“对手国家”是其题中应有之义。"
// }
{
title: "《美国法典》",
info: "第3编第301条",
content:
"允许总统通过行政命令(Executive Order)​​ 或其它书面形式授权行政部门或机构的负责人​(如国务卿、财政部长等)代行本属于总统的法定职能(由国会立法授予总统的职能)。"
},
{
title: "《出口管制改革法案》",
info: "",
content:
"该法案授权政府出于国家安全和外交政策目的对特定技术、商品和软件的出口进行管制。确保AI技术不流向“对手国家”是其题中应有之义。"
}
]);
const handleGetLaws = async () => {
const params = {
id: decreeId.value
}
};
try {
const res = await getDecreeDepend(params)
console.log('法律依据', res);
if(res.code === 200 && res.data) {
const res = await getDecreeDepend(params);
console.log("法律依据", res);
if (res.code === 200 && res.data) {
laws.value = res.data;
} 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(() => {
handleGetBackground();
handleGetRelateEvents()
handleGetLaws()
handleGetRelateEvents();
handleGetLaws();
});
</script>
<style lang="scss" scoped>
.introduction-wrap {
display: flex;
position: relative;
.box-header {
height: 56px;
display: flex;
......@@ -297,28 +328,32 @@ onMounted(() => {
}
}
.left {
width: 1150px;
width: 1064px;
.box1 {
margin-top: 16px;
width: 1150px;
width: 1064px;
height: 414px;
border-radius: 4px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box1-main {
margin-left: 22px;
height: 280px;
width: 1034px;
height: 290px;
overflow: hidden;
overflow-y: auto;
.box1-item {
width: 1101px;
height: 48px;
width: 1015px;
min-height: 48px;
margin-bottom: 8px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 2px;
background: rgba(255, 255, 255, 1);
display: flex;
align-items: center;
padding: 8px 0;
.id {
margin-top: 12px;
margin-left: 15px;
width: 24px;
height: 24px;
......@@ -329,9 +364,12 @@ onMounted(() => {
color: #0a57a6;
}
.title {
width: 1000px;
line-height: 48px;
width: 914px;
line-height: 24px;
margin-left: 13px;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
}
.open {
width: 16px;
......@@ -360,16 +398,16 @@ onMounted(() => {
}
.box2 {
margin-top: 16px;
width: 1150px;
width: 1064px;
height: 415px;
border-radius: 4px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box2-main {
margin-top: 3px;
margin-left: 31px;
height: 330px;
width: 1090px;
width: 1004px;
overflow: hidden;
overflow-y: auto;
.box2-item {
......@@ -386,7 +424,7 @@ onMounted(() => {
}
}
.item-center {
width: 892px;
width: 806px;
margin-left: 14px;
.title {
height: 30px;
......@@ -398,7 +436,7 @@ onMounted(() => {
margin-top: -5px;
}
.content {
width: 892px;
width: 806px;
height: 30px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
......@@ -408,6 +446,7 @@ onMounted(() => {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
}
.item-right {
......@@ -438,24 +477,28 @@ onMounted(() => {
margin-left: 16px;
.box3 {
margin-top: 16px;
width: 576px;
width: 520px;
height: 845px;
border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box3-main {
margin-top: 9px;
width: 520px;
width: 464px;
height: 720px;
// overflow: hidden;
overflow-y: auto;
padding-left: 20px;
.box3-item {
margin-bottom: 24px;
margin-bottom: 20px;
position: relative;
cursor: pointer;
// border-bottom: 1px solid rgba(234, 236, 238, 1);
.id {
width: 24px;
height: 24px;
position: absolute;
left: 28px;
left: 18px;
top: 1px;
z-index: 99;
text-align: center;
......@@ -466,13 +509,16 @@ onMounted(() => {
color: #0a57a6;
}
.item-header {
width: 460px;
width: 384px;
height: 35px;
display: flex;
justify-content: space-between;
margin-left: 60px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.name {
max-width: 460px;
max-width: 384px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
......
......@@ -20,7 +20,7 @@
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import { ref, onMounted } from "vue";
import router from "@/router";
import { useRoute } from "vue-router";
const route = useRoute();
......@@ -41,7 +41,6 @@ const siderList = ref([
const siderBtnActive = ref("政令简介");
const handleClickLeftSiderBtn = item => {
window.sessionStorage.setItem("siderBarActiveName", item.name);
siderBtnActive.value = item.name;
router.push({
path: item.path,
......@@ -52,25 +51,22 @@ const handleClickLeftSiderBtn = item => {
};
onMounted(() => {
if (window.sessionStorage.getItem("siderBarActiveName")) {
siderBtnActive.value = window.sessionStorage.getItem("siderBarActiveName");
}
});
onUnmounted(() => {
if (window.sessionStorage.getItem("siderBarActiveName")) {
window.sessionStorage.removeItem("siderBarActiveName");
if (route.path === "/decreeLayout/overview/introduction") {
siderBtnActive.value = "政令简介";
} else {
siderBtnActive.value = "政令背景";
}
});
</script>
<style lang="scss" scoped>
.decree-overview-wrap {
width: 1920px;
width: 100%;
height: 100%;
overflow: hidden;
background: rgba(247, 248, 249, 1);
display: flex;
justify-content: center;
.left {
width: 160px;
padding-top: 16px;
......
......@@ -26,9 +26,16 @@
</div>
<div class="item">
<div class="item-left">{{ "英文全称:" }}</div>
<div class="item-right text" v-if="basicInfo.eName?.length < 60">
{{ basicInfo.eName }}
</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 class="item">
<div class="item-left">{{ "相关领域:" }}</div>
......@@ -43,9 +50,9 @@
<div class="item-right text">{{ basicInfo.signTime }}</div>
</div>
<div class="item">
<div class="item-left">{{ "签署总统:" }}</div>
<div class="item-left">{{ "发布机构:" }}</div>
<div class="item-right text">
{{ basicInfo.signPeople }}
{{ basicInfo.proposeOrgName }}
</div>
</div>
<div class="item">
......@@ -80,9 +87,9 @@
<div class="box2-item" v-for="(item, index) in curmajorList" :key="index">
<div class="id">{{ index + 1 }}</div>
<div class="title">{{ item.content }}</div>
<div class="open">
<!-- <div class="open">
<img src="./assets/images/open-icon.png" alt="" />
</div>
</div> -->
</div>
</div>
<div class="box2-footer">
......@@ -127,7 +134,7 @@
<div class="box3-top">
<div class="box3-top-top">
<div class="left">
<img :src="box3TopData.logo?box3TopData.logo:DefaultIcon2" alt="" />
<img :src="box3TopData.logo ? box3TopData.logo : DefaultIcon2" alt="" />
</div>
<div class="right">
<div class="name">{{ box3TopData.name }}</div>
......@@ -199,11 +206,10 @@ import box1Img from "./assets/images/box1-img.png";
import Box3Logo from "./assets/images/box3-img.png";
import { getDecreeBasicInfo, getDecreeMainContent, getDecreeOrganization } from "@/api/decree/introduction";
import DefaultIcon1 from '@/assets/icons/default-icon1.png'
import DefaultIcon2 from '@/assets/icons/default-icon2.png'
import DefaultIcon1 from "@/assets/icons/default-icon1.png";
import DefaultIcon2 from "@/assets/icons/default-icon2.png";
const route = useRoute();
const decreeId = ref(route.query.id);
// 基本信息
......@@ -233,6 +239,7 @@ const handleGetBasicInfo = async () => {
basicInfo.value.signTime = res.data.postDate;
basicInfo.value.bh = res.data.order;
basicInfo.value.deadline = res.data.deadline;
basicInfo.value.proposeOrgName = res.data.proposeOrgName;
}
} catch (error) {
console.error("基本信息error", error);
......@@ -287,7 +294,6 @@ const box3BtnActiveIndex = ref(0);
const handleClickBox3Btn = (btn, index) => {
box3ActiveBtn.value = btn;
box3BtnActiveIndex.value = index;
box3TopData.value.logo = box3Data.value[index].url;
box3TopData.value.name = box3Data.value[index].name;
box3TopData.value.eName = box3Data.value[index].ename;
......@@ -297,7 +303,7 @@ const handleClickBox3Btn = (btn, index) => {
eventList.value = box3Data.value[index].newsList.map(val => {
return {
time: val.newsDate,
title: val.newsTitle
title: val.newsContent
};
});
};
......@@ -327,7 +333,6 @@ const eventList = ref([
// time: "2025-07-21",
// title: "美商务部进一步收紧对华先进半导体出口管制,将更多中国实体列入“实体清单”。限制14纳米及以下先进芯片、DRAM等对华出口"
// }
]);
const handleGetOrgnization = async () => {
......@@ -384,10 +389,8 @@ const handleGetOrgnization = async () => {
};
onMounted(() => {
handleGetOrgnization();
})
handleGetOrgnization();
});
</script>
<style lang="scss" scoped>
......@@ -416,12 +419,18 @@ handleGetOrgnization();
}
.header-btn-box {
position: absolute;
z-index: 9999;
width: 320px;
height: 56px;
top: 14px;
right: 84px;
display: flex;
justify-content: flex-end;
flex-wrap: wrap;
gap: 8px;
white-space: nowrap;
.btn {
min-width: min-content;
height: 28px;
padding: 0 8px;
box-sizing: border-box;
......@@ -459,10 +468,10 @@ handleGetOrgnization();
}
}
.left {
width: 1150px;
width: 1064px;
.box1 {
margin-top: 16px;
width: 1150px;
width: 1064px;
height: 414px;
border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
......@@ -470,16 +479,17 @@ handleGetOrgnization();
.box1-main {
display: flex;
.box1-main-left {
width: 235px;
width: 395px;
height: 332px;
margin-left: 42px;
img {
width: 100%;
height: 100%;
// height: 100%;
}
}
.box1-main-right {
margin-left: 40px;
width: 590px;
margin-left: 20px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
......@@ -492,6 +502,12 @@ handleGetOrgnization();
.item-left {
width: 100px;
}
.item-right {
width: 470px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tag-box {
display: flex;
.tag {
......@@ -518,7 +534,7 @@ handleGetOrgnization();
}
.box2 {
margin-top: 16px;
width: 1150px;
width: 1064px;
height: 415px;
border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
......@@ -526,20 +542,23 @@ handleGetOrgnization();
.box2-main {
margin-left: 22px;
height: 280px;
overflow: hidden;
overflow-y: auto;
.box2-item {
width: 1101px;
height: 48px;
width: 1015px;
// height: 48px;
margin-bottom: 8px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 2px;
background: rgba(255, 255, 255, 1);
display: flex;
align-items: center;
padding: 12px 0;
&:nth-child(2n-1) {
background: rgba(247, 248, 249, 1);
}
.id {
margin-top: 12px;
margin-left: 15px;
width: 24px;
height: 24px;
......@@ -551,15 +570,15 @@ handleGetOrgnization();
}
.title {
width: 1020px;
line-height: 48px;
margin-left: 5px;
line-height: 24px;
margin-left: 10px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 700;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
}
.open {
width: 16px;
......@@ -588,17 +607,18 @@ handleGetOrgnization();
}
}
.right {
width: 520px;
margin-left: 16px;
.box3 {
margin-top: 16px;
width: 576px;
width: 520px;
height: 845px;
border-radius: 4px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.box3-top {
margin-top: 10px;
height: 261px;
margin-top: 30px;
height: 241px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
.box3-top-top {
width: 473px;
......@@ -644,6 +664,7 @@ handleGetOrgnization();
}
}
.right {
width: 350px;
margin-left: 22px;
.name {
height: 26px;
......@@ -667,6 +688,9 @@ handleGetOrgnization();
.box3-top-bottom {
margin-left: 50px;
.box3-top-right-main {
height: 150px;
overflow: hidden;
overflow-y: auto;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
......@@ -676,7 +700,7 @@ handleGetOrgnization();
.main-item {
display: flex;
margin-top: 12px;
height: 26px;
// height: 26px;
line-height: 26px;
.item-icon {
width: 4px;
......@@ -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>
\ No newline at end of file
......@@ -159,7 +159,7 @@ import getPieChart from "./utils/piechart";
import getWordCloudChart from "./utils/worldCloudChart";
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 Img1 from "./assets/images/1.png";
......@@ -171,7 +171,7 @@ import Img6 from "./assets/images/6.png";
import Img7 from "./assets/images/7.png";
import Img8 from "./assets/images/8.png";
const route = useRoute()
const route = useRoute();
const box1ChartData = ref({
nodes: [
......@@ -381,19 +381,15 @@ const box3ChartData = ref([
]);
const handleGetOpinions = async () => {
const params = {
orgId: '50754570da464d0a81a5563dcb61d2ec'
}
orgId: "50754570da464d0a81a5563dcb61d2ec"
};
try {
const res = await getGovOrgOpinions(params)
console.log('主要科技政策观点', res);
} catch (error) {
}
}
const res = await getGovOrgOpinions(params);
console.log("主要科技政策观点", res);
} catch (error) {}
};
// 人物关系
const box4ChartData = ref({
nodes: [
{ id: "9", name: "霍华德·卢特尼克", category: 0, symbolSize: 50, symbol: `image://${Img}` },
......@@ -418,18 +414,42 @@ const box4ChartData = ref({
],
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(() => {
handleBox2();
handleGetOpinions()
handleGetOpinions();
const box1Chart = getSankeyChart(box1ChartData.value.nodes, box1ChartData.value.links);
setChart(box1Chart, "box1Chart");
const box3Chart = getWordCloudChart(box3ChartData.value);
setChart(box3Chart, "box3Chart");
const box4Chart = getGraphChart(box4ChartData.value);
setChart(box4Chart, "box4Chart");
handleBox4();
});
</script>
......
......@@ -2,7 +2,7 @@
<div class="wrap">
<div class="header">
<div class="header-left">
<img :src="institutionInfo.logo?institutionInfo.logo: DefaultIcon2" alt="" />
<img :src="institutionInfo.logo ? institutionInfo.logo : DefaultIcon2" alt="" />
</div>
<div class="header-right">
<div class="title">{{ institutionInfo.name }}</div>
......@@ -24,8 +24,8 @@
<div class="tab-box">
<div
class="tab"
@click="handleClickTab(item, index)"
:class="{ tabActive: item.active }"
@click="handleClickTab(item)"
:class="{ tabActive: activeTabName == item.name }"
v-for="(item, index) in tabList"
:key="index"
>
......@@ -41,70 +41,72 @@
</template>
<script setup>
import { ref, computed, onMounted } from "vue";
import { ref, computed, onMounted, onUnmounted } from "vue";
import { useRoute } from "vue-router";
import InsDetail from "./insDetail/index.vue";
import Deepdig from "./deepdig/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({
name: "",
enName: "",
desc: "",
tagList: [],
logo: ''
logo: ""
});
const handleGetInfo = async () => {
const params = {
id: route.query.id
}
};
try {
const res = await getGovOrgBasicInfo(params)
console.log('机构信息', res);
if(res.code === 200 && res.data) {
institutionInfo.value.name = res.data.orgName
institutionInfo.value.enName = res.data.orgNameEn
institutionInfo.value.desc = res.data.orgIntroduction
institutionInfo.value.name = res.data.orgName
}
} catch (error) {
const res = await getGovOrgBasicInfo(params);
console.log("机构信息", res);
if (res.code === 200 && res.data) {
institutionInfo.value.name = res.data.orgName;
institutionInfo.value.enName = res.data.orgNameEn;
institutionInfo.value.desc = res.data.orgIntroduction;
institutionInfo.value.name = res.data.orgName;
}
}
} catch (error) {}
};
handleGetInfo()
handleGetInfo();
const activeTabName = ref("机构详情");
const tabList = ref([
{
name: "机构详情",
active: true
name: "机构详情"
},
{
name: "深度挖掘",
active: false
name: "深度挖掘"
},
{
name: "对话制裁",
active: false
name: "对华制裁"
}
]);
const handleClickTab = (val, index) => {
tabList.value.forEach(item => {
item.active = false;
});
tabList.value[index].active = true;
const handleClickTab = val => {
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>
<style lang="scss" scoped>
......
......@@ -113,7 +113,7 @@
<div class="user-content">
<div class="user-item" v-for="(item, index) in keyUser" :key="index">
<div class="user-item-left">
<img :src="item.avatarUrl" alt="" />
<img :src="item.avatarUrl?item.avatarUrl:DefaultIcon1" alt="" />
</div>
<div class="user-item-right">
<div class="name">{{ item.name }}</div>
......@@ -136,11 +136,13 @@ import User1 from "./assets/images/user1.png";
import User2 from "./assets/images/user2.png";
import User3 from "./assets/images/user3.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 { getGovOrgLatestDynamics, getGovOrgKeyPerson } from "@/api/institution/index";
import { getGovOrgBasicInfo, getGovOrgLatestDynamics, getGovOrgKeyPerson } from "@/api/institution/index";
const route = useRoute()
// 基本信息
const basicInfo = ref({
image: Img,
shijian: "1948年",
......@@ -149,6 +151,28 @@ const basicInfo = ref({
xiashujigou: "工业与安全局、国际贸易管理局、专利商标局等",
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([
......@@ -162,16 +186,6 @@ const keyUser = ref([
// avatarUrl: User2,
// position: "副部长"
// },
// {
// name: "杰弗里·凯斯勒",
// avatarUrl: User3,
// position: "工业与安全局局长"
// },
// {
// name: "约翰·斯奎尔斯",
// avatarUrl: User4,
// position: "专利商标局局长"
// }
]);
const handleGetKeyUser = async () => {
const params = {
......@@ -251,49 +265,7 @@ handleGetKeyUser();
// },
// 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 isCrelated = ref(false);
......@@ -318,6 +290,7 @@ const handleGetLatestDynamics = async () => {
const params = {
orgId: route.query.id,
cRelated: isCrelated.value ? "Y" : "N",
dynamicsType: dynamicsName === '机构动态' ? "org" : "person",
currentPage: 1,
pageSize: 9999999
};
......@@ -330,7 +303,13 @@ const handleGetLatestDynamics = async () => {
}
} catch (error) {}
};
onMounted(() => {
handleGetLatestDynamics();
handleGetBasicInfo()
})
</script>
<style lang="scss" scoped>
......
......@@ -18,17 +18,17 @@
<div class="item">
<div class="item-top">{{ "今年新增" }}</div>
<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-right">{{ "1129家" }}</div>
<div class="item-bottom-right">{{ `${box1Info.currentYear.totalNum}家` }}</div>
</div>
</div>
<div class="item">
<div class="item-top">{{ "今年新增" }}</div>
<div class="item-top">{{ "全部企业" }}</div>
<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-right">{{ "1129家" }}</div>
<div class="item-bottom-right">{{ `${box1Info.allYear.totalNum}家` }}</div>
</div>
</div>
</div>
......@@ -80,17 +80,17 @@
<div class="item">
<div class="item-top">{{ "今年新增" }}</div>
<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-right">{{ "6次" }}</div>
<div class="item-bottom-right">{{ `${box3Info.currentYear.totalNum}次` }}</div>
</div>
</div>
<div class="item">
<div class="item-top">{{ "今年新增" }}</div>
<div class="item-top">{{ "全部调查" }}</div>
<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-right">{{ "91次" }}</div>
<div class="item-bottom-right">{{ `${box3Info.allYear.totalNum}次` }}</div>
</div>
</div>
</div>
......@@ -130,117 +130,245 @@ import { ref, computed, onMounted } from "vue";
import setChart from "@/utils/setChart";
import getPieChart from "./utils/piechart";
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({
title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
title: [],
data: [
{
name: "全部实体",
data: [1104, 468, 602, 635, 486, 622, 811, 967, 952, 1104, 1358, 1196]
data: []
},
{
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([
{
name: "集成电路",
value: 50
},
{
name: "人工智能",
value: 46
},
{
name: "通信网络",
value: 40
},
{
name: "能源",
value: 32
},
{
name: "先进制造",
value: 31
},
{
name: "生物科技",
value: 31
},
{
name: "航空航天",
value: 30
// {
// name: "集成电路",
// value: 50
// },
]);
const handleGetBox2Data = async () => {
const params = {
orgId: route.query.id,
// orgId: 54,
year: 2025
};
try {
const res = await getEntityListField(params);
console.log("实体清单新增企业领域分布", res);
if (res.code === 200 && res.data) {
box2Data.value = res.data.map(item => {
return {
name: item.industry,
value: item.amount
};
});
}
} catch (error) {}
};
const handleBox2 = async () => {
await handleGetBox2Data();
const box2Chart = getPieChart(box2Data.value);
setChart(box2Chart, "box2Chart");
};
const box3Info = ref({
currentYear: {
num: 0,
totalNum: 0
},
{
name: "新材料",
value: 24
allYear: {
num: 0,
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({
title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
title: [],
data: [
{
name: "全部调查",
data: [856, 456, 568, 631, 667, 631, 532, 589, 631, 668, 672, 630]
data: []
},
{
name: "涉华调查",
data: [188, 195, 198, 205, 208, 214, 218, 223, 216, 219, 211, 204]
data: []
}
]
});
const box4Data = ref([
{
name: "集成电路",
value: 50
},
{
name: "人工智能",
value: 46
},
{
name: "通信网络",
value: 40
},
{
name: "能源",
value: 32
},
{
name: "先进制造",
value: 31
},
{
name: "生物科技",
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 handleGetBox3Data = async () => {
const params = {
orgId: route.query.id
// orgId: 54
};
try {
const res = await getGrowth232Trend(params);
console.log("232调查新增数量变数趋势", res);
if (res.code === 200 && res.data) {
box3Data.value.title = res.data.map(item => {
return item.year;
});
box3Data.value.data[0].data = res.data.map(item => {
return item.allNum;
});
box3Data.value.data[1].data = res.data.map(item => {
return item.chinaNum;
});
}
} catch (error) {}
};
const handleBox3 = async () => {
await handleGetBox3Data();
const box3Chart = getMultiLineChart(box3Data.value.title, box3Data.value.data[0].data, box3Data.value.data[1].data);
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);
setChart(box4Chart, "box4Chart");
};
onMounted(() => {
handleBox1();
handleBox2();
handleBox3();
handleBox4();
});
</script>
......
......@@ -69,39 +69,39 @@
</div>
</div>
<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-left">{{ "301调查" }}</div>
<div class="header-right">{{ "52项" }}</div>
<div class="header-left">{{ sortInfo[1]?.sortName }}</div>
<div class="header-right">{{ `${sortInfo[1]?.sortCount}项` }}</div>
</div>
<div class="content-box">
<div class="item">{{ "可能措施: 加征关税、限制进口" }}</div>
<div class="item">{{ sortInfo[1]?.sortMeasure }}</div>
<div class="item">
{{ '依据《1974年贸易法》第301条针对"不合理或不公正贸易做法"' }}
{{ sortInfo[1]?.sortDescription }}
</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-left">{{ "232调查" }}</div>
<div class="header-right">{{ "3项" }}</div>
<div class="header-left">{{ sortInfo[2]?.sortName }}</div>
<div class="header-right">{{ `${sortInfo[2]?.sortCount}项` }}</div>
</div>
<div class="content-box">
<div class="item">{{ "可能措施: 加征关税、限制进口" }}</div>
<div class="item">{{ sortInfo[2]?.sortMeasure }}</div>
<div class="item">
{{ "依据《1962年贸易扩展法》第232条评估进口产品对国家安全影响" }}
{{ sortInfo[2]?.sortDescription }}
</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-left">{{ "337调查" }}</div>
<div class="header-right">{{ "87项" }}</div>
<div class="header-left">{{ sortInfo[0]?.sortName }}</div>
<div class="header-right">{{ `${sortInfo[0]?.sortCount}项` }}</div>
</div>
<div class="content-box">
<div class="item">{{ "可能措施: 排除令、禁止令" }}</div>
<div class="item">{{ sortInfo[0]?.sortMeasure }}</div>
<div class="item">
{{ "依据《1930年关税法》第337条针对知识产权侵权行为" }}
{{ sortInfo[0]?.sortDescription }}
</div>
</div>
</div>
......@@ -111,10 +111,10 @@
<DivideHeader id="position1" class="divide-header" :titleText="'最新动态'"></DivideHeader>
<div class="center-top">
<div class="box1">
<div class="box1-left">
<div class="box1-left" @click="handleSwithCurSurvey('left')">
<img src="./assets/images/box1-left.png" alt="" />
</div>
<div class="box1-right">
<div class="box1-right" @click="handleSwithCurSurvey('right')">
<img src="./assets/images/box1-right.png" alt="" />
</div>
<div class="box1-header">
......@@ -128,68 +128,73 @@
{{ "查看详情 >" }}
</div>
</div>
<el-carousel
ref="carouselRef"
height="395px"
:autoplay="true"
:interval="3000"
arrow="never"
indicator-position="none"
>
<el-carousel-item v-for="(item, index) in box1DataList" :key="index">
<div class="box1-main">
<div class="box1-main-header">
<div class="header-left">
{{ "美国ITC发布对外国制造的半导体器件及其下游产品和组件的337部分终裁" }}
{{ item.SEARCHNAME }}
</div>
<div class="header-right">
<div class="tag1">{{ "337" }}</div>
<div class="tag2">{{ "半导体" }}</div>
<div class="tag1">{{ item.SEARCHSORT }}</div>
<div class="tag2" v-for="(val, idx) in item.searchArea" :key="idx">{{ val }}</div>
</div>
</div>
<div class="info-box">
<div class="info-header">
<div class="icon"></div>
<div class="time">{{ "2025-08-15" }}</div>
<div class="title">{{ "部分终裁" }}</div>
<div class="time">{{ item.PROGRESSDATE }}</div>
<div class="title">{{ item.PROGRESSRESULT }}</div>
</div>
<div class="info-content">
{{
"对本案行政法官于2025年7月31日作出的初裁(No.36)不予复审,即基于申请方撤回,终止本案对美国注册专利号9,093,473第4项申诉的调查。"
}}
{{ item.PROGRESSDETAILS }}
</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 class="list-right">{{ item.SEARCHNUM }}</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "涉及产品:" }}</div>
<div class="list-right">
{{
"对美出口、在美进口及销售的特定外国制造的半导体器件及其下游产品和组件(Certain Foreign-Fabricated ..."
}}
{{ item.PRODUCT }}
</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" }}
{{ item.PLAINTIFF }}
</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "被告:" }}</div>
<div class="list-right">
{{
"中国台湾地区Taiwan Semiconductor Manufacturing Company Limited of Taiwan、美国Apple Inc. of ...."
}}
{{ item.DEFENDANT }}
</div>
</div>
<div class="list-item">
<div class="icon"></div>
<div class="list-left">{{ "涉案专利" }}</div>
<div class="list-right">
{{ "美国注册专利号7745847、9093473、9147747、9184292" }}
{{ item.PATENT }}
</div>
</div>
</div>
</div>
</el-carousel-item>
</el-carousel>
</div>
<div class="box2">
<div class="box2-header">
......@@ -198,25 +203,39 @@
</div>
<div class="title">
<div class="text">{{ "风险信号" }}</div>
<div class="num">{{ warningList.length }}</div>
<div class="num">{{ box2Data.length }}</div>
</div>
</div>
<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
class="item-left"
:class="{
itemLeftStatus1: item.status === '一般风险',
itemLeftStatus2: item.status === '重大风险'
itemLeftStatus3: item.signalLevel === '特别重大',
itemLeftStatus2: item.signalLevel === '重大风险'
}"
>
{{ item.status }}
{{ item.signalLevel }}
</div>
<div class="item-right">
<el-popover
v-if="item.signalTitle?.length > 20"
effect="dark"
:width="480"
:content="item.signalTitle"
placement="top"
>
<template #reference>
<div class="text">
{{ item.title }}
{{ item.signalTitle }}
</div>
<div class="time">{{ item.time }}</div>
</template>
</el-popover>
<div v-else class="text">
{{ item.signalTitle }}
</div>
<div class="time">{{ item.signalTime }}</div>
</div>
</div>
</div>
......@@ -241,16 +260,25 @@
</div>
</div>
<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">
<img :src="news.img" alt="" />
<img :src="news.newsImage ? news.newsImage : DefaultNewsIcon" alt="" />
</div>
<div class="right">
<div class="right-top">
<div class="title">{{ news.title }}</div>
<div class="time">{{ news.from }}</div>
<div class="title">{{ news.newsTitle }}</div>
<div class="time">{{ news.newsDate + " · " + news.newsOrg }}</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>
......@@ -264,15 +292,15 @@
</div>
<div class="box4-main">
<div class="box4-main-item" v-for="(item, index) in messageList" :key="index">
<div class="left">
<img :src="item.img" alt="" />
<div class="left" @click="handleClickPerson()">
<img :src="item.personImage ? item.personImage : DefaultUserIcon" alt="" />
</div>
<div class="right">
<div class="right-top">
<div class="name">{{ item.name }}</div>
<div class="time">{{ item.time }}</div>
<div class="name">{{ item.personName }}</div>
<div class="time">{{ item.time + " · " + item.orgName }}</div>
</div>
<div class="content">{{ item.content }}</div>
<div class="content">{{ item.remarks }}</div>
</div>
</div>
</div>
......@@ -298,11 +326,14 @@
<div class="box5-main">
<div class="box5-main-chart" id="chart1"></div>
<div class="box5-main-btn-box">
<div class="right-box rightBoxActive">
{{ "按月度" }}
</div>
<div class="right-box">
{{ "按年度" }}
<div
class="right-box"
:class="{ rightBoxActive: box5BtnActive === item.value }"
v-for="(item, index) in box5BtnList"
:key="index"
@click="handleChangeBox5Btn(item.value)"
>
{{ item.name }}
</div>
</div>
</div>
......@@ -322,7 +353,12 @@
</div>
<div class="box6-main">
<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
v-for="item in box6YearList"
:key="item.value"
......@@ -355,7 +391,12 @@
<div class="box7-main-left" id="box7Chart1"></div>
<div class="box7-main-right">
<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
v-for="item in box7YearList"
:key="item.value"
......@@ -406,7 +447,7 @@
<div class="box8-main-item" v-for="(item, index) in box8Data" :key="index">
<div class="item-1">
<div class="icon">
<img :src="item.logo" alt="" />
<img :src="item.logo ? item.logo : DefaultCompanyIcon" alt="" />
</div>
<div class="text">
{{ item.name }}
......@@ -428,28 +469,27 @@
<div class="btn-box">
<div
class="btn"
:class="{ btnActive: activeCate === cate }"
:class="{ btnActive: activeCateId === cate.id }"
v-for="(cate, index) in categoryList"
:key="index"
@click="handleClickCate(cate)"
>
{{ cate }}
{{ cate.name }}
</div>
</div>
<div class="select-box">
<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>
<!-- <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
v-for="item in releaseTimeList"
:key="item.value"
......@@ -467,8 +507,18 @@
<div class="title">{{ "发布时间" }}</div>
</div>
<div class="left-box1-main">
<div class="time-label" v-for="(item, index) in surveyYearList" :key="index">
<el-checkbox v-model="item.selected" :label="item.name" size="large" />
<div class="checkbox-group">
<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>
......@@ -478,8 +528,18 @@
<div class="title">{{ "涉及领域" }}</div>
</div>
<div class="left-box2-main">
<div class="area-label" v-for="(item, index) in surveyAreaList" :key="index">
<el-checkbox v-model="item.selected" :label="item.name" size="large" />
<div class="checkbox-group">
<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>
......@@ -493,32 +553,39 @@
<div class="header-item5">{{ "发布日期" }}</div>
</div>
<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="name"
:class="{
name1: val.name === '301',
name2: val.name === '337',
name3: val.name === '232'
name1: val.SORTCODE === '301',
name2: val.SORTCODE === '337',
name3: val.SORTCODE === '232'
}"
>
{{ val.name }}
{{ val.SORTCODE }}
</div>
<div class="title">{{ val.title }}</div>
<div class="title">{{ val.SEARCHNAME }}</div>
</div>
<div class="item-box2">{{ val.num }}</div>
<div class="item-box3">{{ val.area }}</div>
<div class="item-box4">{{ val.status }}</div>
<div class="item-box5">{{ val.releaseDate }}</div>
<div class="item-box2">{{ val.SEARCHID }}</div>
<div class="item-box3">{{ val.searchArea?.toString() }}</div>
<div class="item-box4">{{ val.CASESTATUS }}</div>
<div class="item-box5">{{ val.SEARCHDATEZH }}</div>
</div>
</div>
<div class="right-footer">
<div class="footer-left">
{{ "共105项调查" }}
{{ `共${totalDiscussNum}项调查` }}
</div>
<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>
......@@ -530,8 +597,8 @@
<script setup>
import { onMounted, ref } from "vue";
import setChart from "@/utils/setChart";
import scrollToTop from "@/utils/scrollToTop";
import * as echarts from "echarts";
import router from "@/router";
import DivideHeader from "@/components/DivideHeader.vue";
......@@ -556,15 +623,57 @@ import Logo2 from "./assets/images/logo2.png";
import Logo3 from "./assets/images/logo3.png";
import Logo4 from "./assets/images/logo4.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";
// 返回首页
const handleBackHome = () => {
router.push({
path: "/overview"
});
import DefaultUserIcon from "@/assets/icons/default-icon1.png";
import DefaultCompanyIcon from "@/assets/icons/default-icon2.png";
import DefaultNewsIcon from "@/assets/icons/default-icon-news.png";
// 首页分类
const sortInfo = ref([{}]);
const handleGetStatSort = async () => {
try {
const res = await getStatSort();
console.log("首页分类", res);
sortInfo.value = res.data;
} catch (error) {}
};
const handleClickToDetail = id => {
// 调查进展
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 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({
path: "/marketAccessLayout",
query: {
......@@ -574,8 +683,17 @@ const handleClickToDetail = id => {
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: "关于对中华人民共和国合成阿片类药物供应链...",
time: "一天前",
......@@ -585,70 +703,210 @@ const warningList = ref([
title: "关于调整汽车及汽车零部件进口的公告",
time: "一天前",
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: "关于调整钢铁进口的公告",
time: "一天前",
status: "重大风险"
img: News2,
title: "美参议院通过决议,要求终止特朗普全球关税政策",
content: `参议院以51票赞成、47票反对通过一项决议,旨在终止特朗普实施的全面关税政策,四名......`,
from: "11-4 · 纽约时报"
},
{
title: "关于使用互惠关税规范进口以纠正导致大规模...",
time: "一天前",
status: "重大风险"
img: News3,
title: "美众院通过950亿美元对外援助法案,包含对台军援",
content: `国会众议院在4月通过了大规模对外援助法案,其中包括为“印太安全”提供资金的条款,......`,
from: "11-3 · 洛杉矶时报"
},
{
title: "关于修订对中华人民共和国低价值进口商品适...",
time: "一天前",
status: "一般风险"
img: News4,
title: "“大而美”法案在激烈争议中通过",
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([
{
label: "近半年发布",
value: "近半年发布"
},
{
label: "近一年发布",
value: "近一年发布"
},
{
label: "近两年发布",
value: "近两年发布"
},
const handleGetBox4Data = async () => {
const params = {
moduleId: "0104"
};
try {
const res = await getRemarks(params);
console.log("社交媒体", res);
if (res.code === 200 && res.data) {
messageList.value = res.data;
}
} catch (error) {}
};
// 点击人物头像,跳转到人物主页
const handleClickPerson = () => {
const route = router.resolve({
path: "/characterPage",
query: {
type: 3 // 1 2 3
}
});
window.open(route.href, "_blank");
};
// 调查数量
const box5BtnList = ref([
{
label: "近三年发布",
value: "近三年发布"
name: "按月度",
value: 1
},
{
label: "近五年发布",
value: "近五年发布"
name: "按年度",
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("全部调查");
const activeHylyId = ref("");
// 3. 为每个类别创建值数组
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 => {
console.log(cate);
// 如果找到则返回searchCount,否则返回0
return matchingItem ? matchingItem.searchCount : 0;
});
activeCate.value = cate.hylymc;
activeHylyId.value = cate.hylyid;
handleGetBillsByType();
};
return {
name: category,
value: values
};
});
// 绘制echarts图表
const setChart = (option, chartId) => {
let chartDom = document.getElementById(chartId);
chartDom.removeAttribute("_echarts_instance_");
let chart = echarts.init(chartDom);
chart.setOption(option);
return chart;
};
// 4. 构建最终结果
return {
title: allYears,
data: categoryData
};
}
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({
title: ["2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025"],
......@@ -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",
value: "2025"
......@@ -694,216 +976,101 @@ const box7YearList = ref([
value: "2020"
}
]);
const box7SelectedYear = ref("2025");
const surveyYearList = ref([
{
name: "全部时间",
selected: false
},
{
name: "2025年",
selected: false
},
{
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
},
const handleChangeBox6Year = () => {
handleBox6();
};
const box6Data = ref({
title: [],
data: [
{
name: "显示技术",
selected: false
name: "337调查",
value: []
},
{
name: "新能源",
selected: false
name: "232调查",
value: []
},
{
name: "通信设备",
selected: false
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 surveyInfoList = ref([
{
name: "301",
title: "某些车辆远程信息处理、车队管理以及基于视频的安全系统、设备和组件12",
num: "337-TA-1393",
area: "半导体",
status: "正在调查",
releaseDate: "2025年9月1日"
},
{
name: "337",
title: "某些蒸发器设备,其中使用的墨盒及其组件(II)",
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 arr1 = res.data.filter(item => {
return item.SORTNAME === "337调查";
});
const arr1Name = arr1.map(item => {
return item.AREANAME;
});
box6Data.value.title.forEach((item, index) => {
if (arr1Name.indexOf(item) > -1) {
const idx = arr1Name.indexOf(item);
box6Data.value.data[0].value[index] = arr1[idx].AREACOUNT;
} else {
box6Data.value.data[0].value[index] = 0;
}
]);
});
// 新闻资讯
const newsList = ref([
{
img: News1,
title: "美政府停摆仍持续,拨款法案存缺陷,但两党磋商露曙光",
content: `美国政府停摆已持续34天,距离历史上最长的停摆纪录仅差一天,参议院已先后13次尝试...`,
from: "11-4 · 华盛顿邮报"
},
{
img: News2,
title: "美参议院通过决议,要求终止特朗普全球关税政策",
content: `参议院以51票赞成、47票反对通过一项决议,旨在终止特朗普实施的全面关税政策,四名......`,
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 arr2 = res.data.filter(item => {
return item.SORTNAME === "232调查";
});
const arr2Name = arr2.map(item => {
return item.AREANAME;
});
box6Data.value.title.forEach((item, index) => {
if (arr2Name.indexOf(item) > -1) {
const idx = arr2Name.indexOf(item);
box6Data.value.data[1].value[index] = arr2[idx].AREACOUNT;
} else {
box6Data.value.data[1].value[index] = 0;
}
]);
});
// 社交媒体
const messageList = ref([
{
img: Message1,
name: "唐纳德·特朗普",
time: "15:23 · 发布于真实社交",
content: `埃隆·马斯克在强力支持我竞选总统之前,早就知道我强烈反对‘电动汽车强制令’。这太荒谬了,这一直是我竞选活动的主要部分。电动汽车没问题,但不应该强迫每个人都拥有一辆。埃隆获得的补贴可能远远超过历史上任何一个人。如果没有补贴,埃隆可能不得不关门大吉,回到南非老家。`
},
{
img: Message2,
name: "埃隆·马斯克",
time: "14:49 · 发布于X",
content: `如果这个疯狂的支出法案获得通过,‘美国党’将在第二天成立。`
},
{
img: Message3,
name: "塞巴斯蒂安·马拉比",
time: "11:05 · 发布于X",
content: `提出特朗普政府的AI政策强调技术开放与快速应用,但可能以牺牲安全防范为代价,开启了“潘多拉魔盒”。`
const arr3 = res.data.filter(item => {
return item.SORTNAME === "301调查";
});
const arr3Name = arr3.map(item => {
return item.AREANAME;
});
box6Data.value.title.forEach((item, index) => {
if (arr3Name.indexOf(item) > -1) {
const idx = arr3Name.indexOf(item);
box6Data.value.data[2].value[index] = arr3[idx].AREACOUNT;
} else {
box6Data.value.data[2].value[index] = 0;
}
]);
});
// 查看更多风险信号
const handleToMoreRiskSignal = () => {
const route = router.resolve("/riskSignal");
window.open(route.href, "_blank");
const numArr = res.data.map(item => {
return item.AREACOUNT;
});
box6Data.value.maxNum = Math.max(...numArr);
}
} catch (error) {}
};
// 查看更多新闻资讯
const handleToMoreNews = () => {
const route = router.resolve("/newsBrief");
window.open(route.href, "_blank");
const handleBox6 = async () => {
await handleGetStatArea();
let chart2 = getRadarChart(box6Data.value);
setChart(chart2, "chart2");
};
// 制裁领域分布
const box6SelectedYear = ref("2025");
const box6YearList = ref([
const box7YearList = ref([
{
label: "2025",
value: "2025"
......@@ -930,6 +1097,12 @@ const box6YearList = ref([
}
]);
const box7SelectedYear = ref("2025");
const handleChangeBox7Year = () => {
handleGetBox7Data2();
};
const box7Chart1Data = ref([
{
name: "337调查",
......@@ -972,96 +1145,282 @@ const box7Chart1Data = ref([
}
]);
const box7Chart2Data = ref([
{
name: "广东省",
value: 42
},
{
name: "上海市",
value: 35
},
{
name: "浙江省",
value: 28
},
{
name: "江苏省",
value: 19
},
const box7Chart2Data = ref([]);
const handleGetBox7Data2 = async () => {
const params = {
years: box7SelectedYear.value
};
try {
const res = await getCompanyPlace(params);
console.log("企业地域分布", res);
if (res.code === 200 && res.data) {
box7Chart2Data.value = res.data
.filter(item => {
return item.ORGPROVINCE;
})
.map(item => {
return {
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: "北京市",
value: 15
name: "全部调查",
id: ""
},
{
name: "四川省",
value: 12
name: "301调查",
id: "301"
},
{
name: "山东省",
value: 11
name: "232调查",
id: "232"
},
{
name: "福建省",
value: 8
name: "337调查",
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: "华为技术有限公司",
data337: 12,
data301: 2,
data232: 1
name: "2025年",
id: "2025"
},
{
logo: Logo2,
name: "大疆创新科技有限公司",
data337: 7,
data301: 1,
data232: null
name: "2024年",
id: "2024"
},
{
logo: Logo3,
name: "TCL科技集团股份有限公司",
data337: 6,
data301: 1,
data232: null
name: "2023年",
id: "2023"
},
{
logo: Logo4,
name: "中兴通讯股份有限公司",
data337: 6,
data301: null,
data232: null
name: "2022年",
id: "2022"
},
{
logo: Logo5,
name: "联想集团",
data337: 6,
data301: null,
data232: null
name: "2021年",
id: "2021"
}
]);
onMounted(async () => {
let chart1 = getMultiLineChart(
chart1Data.value.title,
chart1Data.value.data[0].value,
chart1Data.value.data[1].value,
chart1Data.value.data[2].value
);
setChart(chart1, "chart1");
const checkedSurveyYears = ref(["2025"]);
const handleChangeCheckedSurveyYears = () => {
// console.log(checkedSurveyYears.value);
handleGetSurveyList();
};
let chart2 = getRadarChart();
setChart(chart2, "chart2");
const areaList = ref([
// { 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);
setChart(box7Chart1, "box7Chart1");
let box7Chart2 = getBarChart(box7Chart2Data.value);
setChart(box7Chart2, "box7Chart2");
await handleGetAreaList();
handleGetSurveyList();
});
</script>
......@@ -1288,6 +1647,7 @@ onMounted(async () => {
.content-box {
margin-left: 30px;
.item {
width: 485px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
......@@ -1295,6 +1655,9 @@ onMounted(async () => {
font-weight: 400;
line-height: 24px;
margin-top: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
......@@ -1346,6 +1709,7 @@ onMounted(async () => {
.content-box {
margin-left: 30px;
.item {
width: 485px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
......@@ -1353,6 +1717,9 @@ onMounted(async () => {
font-weight: 400;
line-height: 24px;
margin-top: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
......@@ -1405,6 +1772,7 @@ onMounted(async () => {
.content-box {
margin-left: 30px;
.item {
width: 485px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
......@@ -1412,6 +1780,9 @@ onMounted(async () => {
font-weight: 400;
line-height: 24px;
margin-top: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
......@@ -1436,6 +1807,7 @@ onMounted(async () => {
.box1-left {
position: absolute;
left: 0;
z-index: 9999;
top: 220px;
width: 24px;
height: 48px;
......@@ -1449,6 +1821,7 @@ onMounted(async () => {
position: absolute;
right: 0;
top: 220px;
z-index: 9999;
width: 24px;
height: 48px;
cursor: pointer;
......@@ -1519,8 +1892,9 @@ onMounted(async () => {
}
.header-right {
display: flex;
width: 200px;
width: 300px;
justify-content: flex-end;
flex-wrap: wrap;
.tag1 {
height: 24px;
line-height: 24px;
......@@ -1575,6 +1949,7 @@ onMounted(async () => {
line-height: 24px;
}
.title {
width: 200px;
margin-left: 11px;
margin-top: 10px;
height: 24px;
......@@ -1588,6 +1963,8 @@ onMounted(async () => {
.info-content {
width: 909px;
height: 60px;
overflow: hidden;
overflow-y: auto;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
......@@ -1602,8 +1979,10 @@ onMounted(async () => {
margin-left: 28px;
width: 940px;
height: 185px;
overflow: hidden;
overflow-y: auto;
.list-item {
height: 37px;
min-height: 37px;
display: flex;
.icon {
width: 4px;
......@@ -1708,9 +2087,9 @@ onMounted(async () => {
&:hover {
background: var(--color-bg-hover);
}
.itemLeftStatus1 {
color: rgba(82, 196, 26, 1) !important;
background: rgba(246, 255, 237, 1) !important;
.itemLeftStatus3 {
background: rgba(255, 241, 240) !important;
color: rgba(245, 34, 45, 1) !important;
}
.itemLeftStatus2 {
color: rgba(250, 140, 22, 1) !important;
......@@ -1722,8 +2101,8 @@ onMounted(async () => {
width: 40px;
height: 40px;
border-radius: 20px;
background: rgba(255, 241, 240);
color: rgba(245, 34, 45, 1);
color: rgba(82, 196, 26, 1);
background: rgba(246, 255, 237, 1);
font-family: Microsoft YaHei;
font-size: 12px;
font-weight: 400;
......@@ -1739,15 +2118,18 @@ onMounted(async () => {
border-bottom: 1px solid rgba(240, 242, 244, 1);
display: flex;
.text {
width: 348px;
width: 328px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
font-weight: 400;
line-height: 47px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.time {
margin-left: 10px;
margin-left: 2px;
line-height: 47px;
color: rgba(132, 136, 142, 1);
font-family: Microsoft YaHei;
......@@ -1855,6 +2237,10 @@ onMounted(async () => {
width: 749px;
margin-left: 21px;
border-bottom: 1px solid rgba(240, 242, 244, 1);
cursor: pointer;
&:hover {
background: var(--color-bg-hover);
}
.left {
width: 72px;
height: 48px;
......@@ -1873,7 +2259,7 @@ onMounted(async () => {
justify-content: space-between;
.title {
margin-top: 13px;
width: 520px;
width: 470px;
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
......@@ -1885,15 +2271,18 @@ onMounted(async () => {
white-space: nowrap;
}
.time {
flex: 1;
width: 187px;
text-align: right;
height: 22px;
margin-top: 19px;
margin-top: 15px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
font-size: 14px;
font-weight: 400;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.right-footer {
......@@ -1962,6 +2351,7 @@ onMounted(async () => {
}
.box4-main {
height: 402px;
overflow: hidden;
overflow-y: auto;
box-sizing: border-box;
padding-top: 8px;
......@@ -1973,6 +2363,9 @@ onMounted(async () => {
margin-top: 5px;
width: 36px;
height: 36px;
border-radius: 18px;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
height: 100%;
......@@ -2512,7 +2905,8 @@ onMounted(async () => {
}
.home-main-footer {
// width: 100%;
height: 1149px;
// height: 1149px;
padding-bottom: 20px;
background: rgba(248, 249, 250, 1);
overflow: hidden;
.home-main-footer-header {
......@@ -2555,27 +2949,70 @@ onMounted(async () => {
height: 42px;
box-sizing: border-box;
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 {
width: 1600px;
margin-bottom: 20px;
height: 985px;
// box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
// background: rgba(255, 255, 255, 1);
// height: 985px;
margin: 0 auto;
box-sizing: border-box;
// padding: 20px;
display: flex;
.left {
width: 300px;
height: 560px;
height: 700px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
.left-box1 {
margin-top: 17px;
height: 260px;
height: 220px;
.left-box1-header {
display: flex;
.icon {
......@@ -2597,10 +3034,7 @@ onMounted(async () => {
}
.left-box1-main {
margin-top: 10px;
.time-label {
height: 35px;
margin-left: 25px;
}
padding-left: 20px;
}
}
.left-box2 {
......@@ -2627,17 +3061,15 @@ onMounted(async () => {
}
.left-box2-main {
margin-top: 10px;
.area-label {
height: 35px;
margin-left: 25px;
}
padding-left: 20px;
}
}
}
.right {
margin-left: 16px;
width: 1284px;
height: 899px;
min-height: 700px;
// height: 899px;
border-radius: 10px;
box-shadow: 0px 0px 15px 0px rgba(60, 87, 126, 0.2);
background: rgba(255, 255, 255, 1);
......@@ -2698,12 +3130,16 @@ onMounted(async () => {
}
}
.right-main {
height: 780px;
// background: orange;
min-height: 586px;
border-bottom: 1px solid rgba(230, 231, 232, 1);
// height: 780px;
.item {
display: flex;
padding: 16px 0;
// height: 56px;
cursor: pointer;
&:hover{
background: var(--color-bg-hover) !important;
}
&:nth-child(2n) {
background: rgba(247, 248, 249, 1);
}
......@@ -2797,9 +3233,10 @@ onMounted(async () => {
}
}
.right-footer {
box-sizing: border-box;
padding-top: 15px;
height: 60px;
display: flex;
// height: 60px;
// background: orange;
justify-content: space-between;
.footer-left {
color: rgba(59, 65, 75, 1);
......
......@@ -8,7 +8,7 @@ const getBarChart = (originalData) => {
tooltip: {},
grid: {
top: '3%',
right: '3%',
right: 66,
bottom: '1%',
left: '1%',
containLabel: true
......
import * as echarts from 'echarts'
const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
const getMultiLineChart = (data) => {
console.log('dataaaa',data);
return {
tooltip: {
trigger: 'axis',
......@@ -13,9 +15,9 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
},
grid: {
top: '15%',
right: '5%',
right: '3%',
bottom: '5%',
left: '5%',
left: '3%',
containLabel: true
},
legend: {
......@@ -28,7 +30,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
{
type: 'category',
boundaryGap: false,
data: dataX
data: data.title
}
],
yAxis: [
......@@ -38,7 +40,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
],
series: [
{
name: '337调查',
name: data.data[0].name,
type: 'line',
areaStyle: {
......@@ -53,10 +55,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
emphasis: {
focus: 'series'
},
data: dataY1
data: data.data[0].value
},
{
name: '301调查',
name: data.data[1].name,
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
......@@ -70,10 +72,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
emphasis: {
focus: 'series'
},
data: dataY2
data: data.data[1].value,
},
{
name: '232调查',
name: data.data[2].name,
type: 'line',
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
......@@ -87,7 +89,7 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
emphasis: {
focus: 'series'
},
data: dataY3
data: data.data[2].value,
}
]
}
......
const getRadarChart = () => {
const indicators = [
{ name: "集成电路", max: 10 },
{ name: "能源领域", max: 10 },
{ name: "量子科技", max: 10 },
{ name: "通信网络", max: 10 },
{ name: "人工智能", max: 10 },
{ name: "生物科技", max: 10 }
];
const getRadarChart = (data) => {
// const indicators = [
// { 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 data301 = [5, 3, 7, 8, 7, 9];
const data232 = [4, 10, 3, 4, 2, 5];
......@@ -67,9 +72,10 @@ const getRadarChart = () => {
},
series: [
{
name: "337调查",
// name: "337调查",
name: data.data[0].name,
type: "radar",
data: [{ value: data337 }],
data: [{ value: data.data[0].value }],
lineStyle: {
width: 2,
color: "rgba(5, 95, 194,1)"
......@@ -80,9 +86,9 @@ const getRadarChart = () => {
}
},
{
name: "301调查",
name: data.data[1].name,
type: "radar",
data: [{ value: data301 }],
data: [{ value: data.data[1].value }],
lineStyle: {
width: 2,
color: "rgba(250, 140, 22, 1)"
......@@ -93,9 +99,9 @@ const getRadarChart = () => {
}
},
{
name: "232调查",
name: data.data[2].name,
type: "radar",
data: [{ value: data232 }],
data: [{ value: data.data[2].value }],
lineStyle: {
width: 2,
color: "rgba(146, 84, 222, 1)"
......
......@@ -3,19 +3,24 @@
<div class="header">
<div class="header-top">
<div class="header-top-left">
<div class="title">{{ "中美经济竞争:复杂经济和地缘政治关系中的收益和风险" }}</div>
<img :src="thinkInfo.contentUrl" alt="" />
<div>
<div class="title">{{ thinkInfo.name }}</div>
<div class="en-title">
{{ "U.S.-China Economic CompetitionGains and Risks in a Complex Economic and Geopolitical Relationship" }}
{{ thinkInfo.ename }}
</div>
<div class="tag-box">
<div class="tag">{{ "外交" }}</div>
<div class="tag">{{ "军事" }}</div>
<div class="tag">{{ "经济" }}</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">{{ "兰德科技智库" }}</div>
<div class="time">{{ "2025年6月23日" }}</div>
<div class="name">{{ thinkInfo.thinkTankName }}</div>
<div class="time">{{ thinkInfo.times }}</div>
</div>
</div>
<div class="header-bottom">
......@@ -81,6 +86,9 @@ import {
import { useRouter } from "vue-router";
const router = useRouter();
const reportUrl = ref('')
const thinkInfo = ref({})
// 获取报告全局信息
const handleGetThinkTankReportSummary = async () => {
try {
......@@ -89,6 +97,7 @@ const handleGetThinkTankReportSummary = async () => {
console.log("报告全局信息", res);
if (res.code === 200 && res.data) {
reportUrl.value = res.data.reportUrl
thinkInfo.value = res.data
}
} catch (error) {
console.error("获取报告全局信息error", error);
......@@ -96,7 +105,15 @@ const handleGetThinkTankReportSummary = async () => {
};
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("报告分析");
......@@ -124,13 +141,21 @@ onMounted(async () => {
.header-top {
margin-top: 20px;
margin-left: 248px;
margin-left: 160px;
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;
......@@ -142,6 +167,7 @@ onMounted(async () => {
}
.en-title {
margin-left: 20px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
......@@ -156,6 +182,7 @@ onMounted(async () => {
margin-top: 11px;
display: flex;
gap: 8px;
margin-left: 20px;
.tag {
height: 26px;
......
......@@ -43,14 +43,14 @@
</div>
</div>
</div>
<div class="right">
<!-- <div class="right">
<div class="text">
{{ "查看智库原文" }}
</div>
<div class="icon">
<img src="@/assets/icons/open.png" alt="" />
</div>
</div>
</div> -->
</div>
</div>
......@@ -76,26 +76,26 @@
<div class="point">
<img src="@/assets/images/dot.png" alt="" />
</div>
<div class="line" v-if="index < 5"></div>
<div class="line"></div>
</div>
<div class="box2-item-center">
<div class="title">{{ item.sjbt }}</div>
<div class="content">{{ item.sjnr }}</div>
<div class="title">{{ item.newsTitle }}</div>
<div class="content">{{ item.newsContent }}</div>
</div>
<div class="box2-item-right">
<div class="time">{{ item.time }}</div>
<div class="time">{{ item.newsDate }}</div>
<div class="img-box">
<img :src="item.imageUrl" alt="" />
<img :src="item.newsImage" alt="" />
</div>
</div>
</div>
</div>
<div class="box2-footer">
<!-- <div class="box2-footer">
<div class="text">{{ "查看更多" }}</div>
<div class="icon">
<img src="@/assets/images/icon-double-down.png" alt="" />
</div>
</div>
</div> -->
</div>
</div>
</template>
......@@ -277,42 +277,42 @@ const handleGetThinkTankReportPolicy = async () => {
// 相关政策动态
const box2Data = ref([
{
title: "这是示例标题a",
content: "这是示例内容",
time: "2025-08-30",
img: 1
},
{
title: "这是示例标题a",
content: "这是示例内容",
time: "2025-08-30",
img: 1
},
{
title: "这是示例标题a",
content: "这是示例内容",
time: "2025-08-30",
img: 1
},
{
title: "这是示例标题a",
content: "这是示例内容",
time: "2025-08-30",
img: 1
},
{
title: "这是示例标题a",
content: "这是示例内容",
time: "2025-08-30",
img: 1
},
{
title: "这是示例标题a",
content: "这是示例内容",
time: "2025-08-30",
img: 1
}
// {
// title: "这是示例标题a",
// content: "这是示例内容",
// time: "2025-08-30",
// img: 1
// },
// {
// title: "这是示例标题a",
// content: "这是示例内容",
// time: "2025-08-30",
// img: 1
// },
// {
// title: "这是示例标题a",
// content: "这是示例内容",
// time: "2025-08-30",
// img: 1
// },
// {
// title: "这是示例标题a",
// content: "这是示例内容",
// time: "2025-08-30",
// img: 1
// },
// {
// title: "这是示例标题a",
// content: "这是示例内容",
// time: "2025-08-30",
// img: 1
// },
// {
// title: "这是示例标题a",
// content: "这是示例内容",
// time: "2025-08-30",
// img: 1
// }
]);
const handleGetThinkTankReportPolicyAction = async () => {
......@@ -429,13 +429,16 @@ onMounted(async () => {
.box1-main {
width: 1056px;
height: 1280px;
min-height: 738px;
max-height: 1280px;
padding-bottom: 20px;
margin: 0 auto;
overflow: hidden;
overflow-y: auto;
.box1-item {
height: 128px;
align-items: center;
// height: 128px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
display: flex;
position: relative;
......@@ -462,7 +465,7 @@ onMounted(async () => {
.title {
margin-top: 16px;
height: 24px;
// height: 24px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 18px;
......
......@@ -38,12 +38,12 @@
</div>
</div>
<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"
@click="handleClickArea(item.status)">
{{ item.industryName }}
</div>
</div>
</div> -->
<div class="box2-content" id="box2Chart"></div>
</div>
</div>
......@@ -82,10 +82,10 @@
</div>
<div class="right">
<div class="tag" v-for="(val, idx) in item.hylyList" :key="idx">
{{ val.name }}
{{ val }}
</div>
<div class="tag" v-for="(val, idx) in item.serialNum" :key="idx">
{{ val.name }}
{{ val }}
</div>
</div>
<div class="more">
......@@ -94,7 +94,7 @@
</div>
</div>
<div class="box3-main-footer">
<div class="info">{{ total }}项调查</div>
<div class="info">{{ total }}条建议</div>
<div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" />
......@@ -197,7 +197,7 @@ const handleGetThinkTankReportIndustryCloud = async () => {
try {
const params = {
id: router.currentRoute._value.params.id,
industryId: activeArea.value
// industryId: activeArea.value
};
const res = await getThinkTankReportIndustryCloud(params);
console.log("科技领域词云", res);
......@@ -372,6 +372,7 @@ const majorOpinions = ref([
]);
// 处理页码改变事件
const currentPage = ref(1);
const total = ref(0)
const handleCurrentChange = page => {
currentPage.value = page;
handleGetThinkDynamicsReport();
......@@ -380,9 +381,10 @@ const handleCurrentChange = page => {
const handleGetThinkTankReportContent = async () => {
try {
const res = await getThinkTankReportContent(router.currentRoute._value.params.id);
console.log("主要观点", res);
console.log("主要观点", res.data);
if (res.code === 200 && res.data) {
majorOpinions.value = res.data.content;
total.value = res.data.totalElements
}
} catch (error) {
console.error("获取主要观点error", error);
......@@ -588,7 +590,7 @@ onMounted(() => {
.box2-content {
width: 430px;
height: 231px;
height: 315px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 4px;
......@@ -644,15 +646,18 @@ onMounted(() => {
}
.center {
width: 770px;
height: 64px;
width: 910px;
margin-left: 13px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: flex;
align-items: center;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
.title {
margin-top: 12px;
height: 26px;
// height: 55px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-size: 16px;
......@@ -661,8 +666,12 @@ onMounted(() => {
letter-spacing: 0px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
// text-overflow: ellipsis;
// white-space: nowrap;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.desc {
......@@ -685,8 +694,11 @@ onMounted(() => {
width: 180px;
height: 22px;
display: flex;
gap: 8px;
justify-content: flex-end;
margin-top: 26px;
margin-left: 20px;
height: 22px;
display: flex;
.tag {
height: 22px;
......
......@@ -111,6 +111,7 @@
<img :src="item.imageUrl" alt="" />
</div>
<div class="item-right">
<div>
<div class="title">{{ item.content }}</div>
<div class="info">{{ item.times }} · {{ item.name }}</div>
<div class="tag-box">
......@@ -135,10 +136,16 @@
</div>
</div>
</div>
<div>
<div class="more" @click="toDetaile(item.reportId)">
<img src="@/assets/icons/open.png" alt="" />
</div>
</div>
</div>
</div>
</div>
<div class="right-footer">
<div class="info">{{ total }}智库报告</div>
<div class="info">{{ total }}篇政策建议</div>
<div class="page-box">
<el-pagination :page-size="12" background layout="prev, pager, next" :total="total"
@current-change="handleCurrentChange" :current-page="currentPage" />
......@@ -528,6 +535,17 @@ function getDateMonthsAgo(months) {
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 sort = ref(true);
const currentPage = ref(1);
......@@ -813,7 +831,8 @@ onMounted(() => {
.right {
width: 1284px;
height: 1670px;
max-height: 1670px;
margin-bottom: 20px;
box-sizing: border-box;
border: 1px solid rgba(234, 236, 238, 1);
border-radius: 10px;
......@@ -823,10 +842,10 @@ onMounted(() => {
.right-main {
margin: 17px auto;
width: 1209px;
height: 1540px;
max-height: 1540px;
.right-main-item {
height: 154px;
// height: 154px;
box-sizing: border-box;
padding-top: 8px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
......@@ -845,6 +864,9 @@ onMounted(() => {
.item-right {
margin-left: 15px;
display: flex;
width: 100%;
justify-content: space-between;
.title {
// height: 24px;
......
......@@ -21,7 +21,10 @@ const getMultiLineChart = (dataX, dataY1, dataY2, dataY3) => {
legend: {
show: true,
top: 10,
left:'10%'
left:'10%',
textStyle: {
fontSize: 16
}
},
xAxis: [
{
......
......@@ -14,13 +14,20 @@ const getPieChart = (data) => {
label: {
alignTo: 'edge',
formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
minMargin: 5,
edgeDistance: 10,
lineHeight: 15,
minMargin: 10,
edgeDistance: 20,
lineHeight: 24,
rich: {
name: {
fontSize: 16,
color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei',
fontWeight: 700
},
time: {
fontSize: 10,
color: '#999'
fontSize: 16,
color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei',
}
}
},
......
......@@ -154,8 +154,8 @@
<div class="box3-main-left" id="box3Chart"></div>
<div class="box3-main-right">
<div class="box3-right-item" v-for="(item, index) in box3RightData" :key="index">
<div class="icon">
<img :src="item.imageUrl" alt="" />
<div class="icon" @click="handleClickPerson">
<img :src="item.imageUrl?item.imageUrl:DefaultIcon1" alt="" />
</div>
<div class="info">
<div class="info-header">
......@@ -188,6 +188,8 @@ import {
import { useRouter } from "vue-router";
import DefaultIcon1 from '@/assets/icons/default-icon1.png'
const router = useRouter();
import InfoImg from "./images/img.png";
import Icon1 from "./images/icon1.png";
......@@ -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(() => {
handleGetThinkTankInfoBasic()
handleGetThinkTankInfoBranch()
......@@ -788,9 +801,9 @@ onMounted(() => {
.box1-main-right {
margin-left: 38px;
margin-top: 26px;
margin-top: 6px;
width: 800px;
height: 270px;
height: 300px;
}
}
......@@ -950,6 +963,7 @@ onMounted(() => {
width: 48px;
height: 48px;
margin-left: 8px;
cursor: pointer;
img {
width: 100%;
......
......@@ -3,7 +3,7 @@ const getPieChart = (data) => {
series: [
{
type: 'pie',
radius: [70, 100],
radius: [80, 110],
height: '100%',
left: 'center',
width: '100%',
......@@ -13,7 +13,13 @@ const getPieChart = (data) => {
},
label: {
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,
edgeDistance: 10,
lineHeight: 15,
......@@ -22,10 +28,12 @@ const getPieChart = (data) => {
fontSize: 16,
color: 'rgba(59, 65, 75, 1)',
fontWeight: 700,
lineHeight: 20
},
time: {
fontSize: 14,
color: 'rgba(59, 65, 75, 1)',
lineHeight: 20
}
}
},
......
......@@ -78,7 +78,7 @@
<div class="title-right">{{ item.country }}</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>
<div class="content">{{ item.desc }}</div>
</template>
......@@ -114,7 +114,7 @@
<div class="title">{{ "智库发布" }}</div>
</div>
<div class="box1-header-right">
<div class="box1-header-right" @click="toDetaile()">
查看详情 >
</div>
</div>
......@@ -129,7 +129,7 @@
<div class="title">{{ box1Data[box1DataIndex]?.reportName }}</div>
<div class="tag-box">
<div class="tag" v-for="(item, index) in box1Data[box1DataIndex]?.industryVOList" :key="index">
{{ item }}
{{ item.industryName }}
</div>
</div>
<div class="content">{{ box1Data[box1DataIndex]?.summary }}</div>
......@@ -139,6 +139,7 @@
<div class="logo">
<img :src="box1Data[box1DataIndex]?.thinkTankImage" alt="" />
</div>
<div class="text">{{ box1Data[box1DataIndex]?.thinkTankName }}</div>
<div class="text">{{ box1Data[box1DataIndex]?.reportDate }}</div>
</div>
</div>
......@@ -168,9 +169,14 @@
{{ item.status || "一般风险" }}
</div>
<div class="item-right">
<el-popover effect="dark" :width="500" :content="item.title" placement="top-start">
<template #reference>
<div class="text">
{{ item.title }}
</div>
</template>
</el-popover>
<div class="time">{{ item.time }}</div>
</div>
</div>
......@@ -196,7 +202,7 @@
</div>
</div>
<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">
<img :src="news.newsImage !== null ? news.newsImage : defaultNewsIcon" />
</div>
......@@ -205,7 +211,13 @@
<div class="title">{{ news.newsTitle }}</div>
<div class="time">{{ news.newsOrg }}</div>
</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>
......@@ -231,7 +243,7 @@
</div> -->
<div class="box4-main">
<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="" />
</div>
<div class="right">
......@@ -314,11 +326,16 @@
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }">
{{ index + 1 }}
</div>
<!-- <el-popover effect="dark" :content="item.clause" placement="top-start">
<template #reference> -->
<div class="item-center"
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }">
{{ item.clause }}
</div>
<div class="item-right">{{ `${item.count}份报告 >` }}</div>
<!-- </template>
</el-popover> -->
<!-- <div class="item-right">{{ `${item.count}份报告 >` }}</div> -->
</div>
</div>
</div>
......@@ -388,9 +405,14 @@
<div class="footer-card-top">
<img :src="item.imageUrl" alt="" />
</div>
<el-popover effect="dark" :content="item.name" placement="top-start">
<template #reference>
<div class="footer-card-title">
{{ item.name }}
</div>
</template>
</el-popover>
<div class="footer-card-footer">
<div class="time">{{ item.times }}</div>
<div class="from">{{ item.thinkTankName }}</div>
......@@ -431,6 +453,7 @@ import {
getThinkTankReportNews,
getThinkTankReportRemarks
} from "@/api/thinkTank/overview";
import { getPersonSummaryInfo } from "@/api/common/index";
import getMultiLineChart from "./utils/multiLineChart";
import getPieChart from "./utils/piechart";
......@@ -567,6 +590,17 @@ function changeBox1Data(type) {
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([
{
......@@ -977,78 +1011,80 @@ const box7Data = ref({
{ source: "美国国务院", target: "兰德公司", value: 15 }
]
});
function transformThinkTankData(data) {
// 遍历每个智库
function transformDataToSankey(inputData) {
const nodes = [];
const links = [];
const nodeSet = new Set(); // 用于去重
// 遍历每个智库
data.forEach(thinkTank => {
const thinkTankName = thinkTank.thinkTankName;
// 遍历输入数据
inputData.forEach(item => {
const thinkTankName = item.thinkTankName;
// 添加智库节点
if (!nodeSet.has(thinkTankName)) {
// 添加智库节点(如果尚未添加)
if (!nodes.some(node => node.name === thinkTankName)) {
nodes.push({ name: thinkTankName });
nodeSet.add(thinkTankName);
}
// 遍历每个资金来源
thinkTank.thinkTankDonationSourceVOList.forEach(source => {
const { amount, institution, secondInstitution } = source;
// 遍历捐赠来源
item.thinkTankDonationSourceVOList.forEach(donation => {
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 });
nodeSet.add(institution);
}
// 处理二级机构节点
if (secondInstitution && !nodeSet.has(secondInstitution)) {
// 如果存在二级机构,也添加二级机构节点(如果尚未添加)
if (secondInstitution && !nodes.some(node => node.name === secondInstitution)) {
nodes.push({ name: secondInstitution });
nodeSet.add(secondInstitution);
}
// 构建链接
if (institution && secondInstitution) {
// 情况1: institution → secondInstitution → thinkTankName
// 添加链接
if (secondInstitution) {
// 如果存在二级机构,先从捐赠机构到二级机构
if (institution !== secondInstitution) { // 检查自引用
links.push({
source: institution,
target: secondInstitution,
value: amount
});
}
// 再从二级机构到智库
if (secondInstitution !== thinkTankName) { // 检查自引用
links.push({
source: secondInstitution,
target: thinkTankName,
value: amount
});
} else if (institution && !secondInstitution) {
// 情况2: institution → thinkTankName
}
} else {
// 如果没有二级机构,直接从捐赠机构到智库
if (institution !== thinkTankName) { // 检查自引用
links.push({
source: institution,
target: thinkTankName,
value: amount
});
} else if (!institution && !secondInstitution) {
// 情况3: 只有智库节点
links.push({
source: thinkTankName,
value: amount
});
}
}
});
});
console.log(nodes, links, 'nodes, linksnodes, links')
return { nodes, links };
}
// 智库资金流向
const handleGetThinkTankDonation = async () => {
try {
const res = await getThinkTankDonation();
console.log("智库资金流向", res);
console.log("智库资金流向", res.data, transformDataToSankey(res.data));
if (res.code === 200 && res.data) {
box7Data.value = transformThinkTankData(res.data);
box7Data.value = transformDataToSankey(res.data);
}
} catch (error) {
console.error("获取智库资金流向error", error);
......@@ -1386,6 +1422,79 @@ const handleToMoreRiskSignal = () => {
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 route = router.resolve({
name: "ReportDetail",
......@@ -2012,11 +2121,11 @@ onMounted(async () => {
display: flex;
justify-content: flex-end;
gap: 6px;
height: 36px;
.logo {
margin-top: 5px;
width: 16px;
height: 16px;
width: 36px;
height: 36px;
img {
width: 100%;
......@@ -2025,6 +2134,7 @@ onMounted(async () => {
}
.text {
margin-top: 6px;
height: 24px;
color: rgba(95, 101, 108, 1);
font-family: Microsoft YaHei;
......@@ -2176,6 +2286,7 @@ onMounted(async () => {
}
.time {
width: 90px;
margin-left: 10px;
line-height: 47px;
color: rgba(132, 136, 142, 1);
......@@ -2357,6 +2468,7 @@ onMounted(async () => {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
}
}
......@@ -2494,6 +2606,9 @@ onMounted(async () => {
margin-top: 5px;
width: 36px;
height: 36px;
border-radius: 18px;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
......@@ -2837,7 +2952,7 @@ onMounted(async () => {
.item-center {
margin-left: 20px;
width: 315px;
width: 425px;
height: 24px;
color: rgba(59, 65, 75, 1);
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,11 +16,18 @@ const getPieChart = (data) => {
formatter: '{name|{b}}\n{time|{c} 条 {d}%}',
minMargin: 5,
edgeDistance: 10,
lineHeight: 15,
lineHeight: 24,
rich: {
name: {
fontSize: 16,
color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei',
fontWeight: 700
},
time: {
fontSize: 10,
color: '#999'
fontSize: 16,
color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei',
}
}
},
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论