提交 1a229cdb authored 作者: 付康's avatar 付康

合并分支 'fk-dev' 到 'pre'

Fk dev 查看合并请求 !331
流水线 #414 已通过 于阶段
in 3 分 20 秒
......@@ -12,11 +12,15 @@ export function search(data) {
})
}
/**
* @param { type } 4:智库列表 6:科技人物所属机构
*/
// 智库列表
export function getThinkTankList() {
export function getThinkTankList(params) {
return request({
method: 'GET',
url: `/temporarySearch/search-info/all-organization-names`,
params
})
}
......@@ -66,4 +70,20 @@ export function getControlReason() {
method: 'GET',
url: `/temporarySearch/search-info/all-controlReason`,
})
}
// 科技人物-人物类别
export function getPersonType() {
return request({
method: 'GET',
url: `/temporarySearch/search-info/all-personType`,
})
}
// 科技企业-企业类型
export function getBusinessType() {
return request({
method: 'GET',
url: `/temporarySearch/search-info/all-businessType`,
})
}
\ No newline at end of file
......@@ -151,15 +151,15 @@ const handleToNewsAnalysis = (item, index) => {
&:hover {
background: var(--color-bg-hover);
.right-top .title {
.right-top > .title {
text-decoration: underline;
color: rgb(5, 95, 194) !important;
font-weight: 700;
}
.right-top .text-inner {
border-bottom-color: rgb(5, 95, 194) !important;
}
// .right-top .text-inner {
// border-bottom-color: rgb(5, 95, 194) !important;
// }
}
.left {
......
// 企业资源库
const DataCompany = () => import('@/views/dataLibrary/company/index.vue')
const dataCompanyRoutes = [
// 企业资源库路由
{
path: "/dataLibrary/dataCompany",
name: "DataCompany",
component: DataCompany,
meta: {
title: '科技企业', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
]
export default dataCompanyRoutes
\ No newline at end of file
// 机构资源库
const DataIns = () => import('@/views/dataLibrary/institution/index.vue')
const dataInsRoutes = [
// 机构资源库路由
{
path: "/dataLibrary/dataInstitution",
name: "DataIns",
component: DataIns,
meta: {
title: '政府机构', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
]
export default dataInsRoutes
\ No newline at end of file
// 新闻资源库
const DataNews = () => import('@/views/dataLibrary/news/index.vue')
const dataNewsRoutes = [
// 新闻资源库路由
{
path: "/dataLibrary/dataNews",
name: "DataNews",
component: DataNews,
meta: {
title: '新闻', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
]
export default dataNewsRoutes
\ No newline at end of file
// 风险信号资源库
const DataRiskSignal = () => import('@/views/dataLibrary/riskSignal/index.vue')
const dataRiskSignalRoutes = [
// 风险信号资源库路由
{
path: "/dataLibrary/dataRiskSignal",
name: "DataRiskSignal",
component: DataRiskSignal,
meta: {
title: '风险信号', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
]
export default dataRiskSignalRoutes
\ No newline at end of file
// 法案资源库
const CongressMan = () => import('@/views/dataLibrary/technologyFigures/congressMan/index.vue')
const Minister = () => import('@/views/dataLibrary/technologyFigures/minister/index.vue')
const TechnologyLeader = () => import('@/views/dataLibrary/technologyFigures/technologyLeader/index.vue')
const ThinkTankResearcher = () => import('@/views/dataLibrary/technologyFigures/thinkTankResearcher/index.vue')
// 风险信号资源库
const DataTechnologyFigures = () => import('@/views/dataLibrary/technologyFigures/index.vue')
const dataDecreeRoutes = [
// 科技法案资源库路由
const dataTechnologyFiguresRoutes = [
// 风险信号资源库路由
{
path: "/dataLibrary/congressMan",
name: "CongressMan",
component: CongressMan,
path: "/dataLibrary/dataTechnologyFigures",
name: "DataTechnologyFigures",
component: DataTechnologyFigures,
meta: {
title: '国会议员', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
{
path: "/dataLibrary/minister",
name: "Minister",
component: Minister,
meta: {
title: '机构主官', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
{
path: "/dataLibrary/technologyLeader",
name: "TechnologyLeader",
component: TechnologyLeader,
meta: {
title: '科技企业领袖', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
},
{
path: "/dataLibrary/thinkTankResearcher",
name: "ThinkTankResearcher",
component: ThinkTankResearcher,
meta: {
title: '智库研究人员', // 显示在tag上的文字
title: '科技人物', // 显示在tag上的文字
affix: false, // 是否为固定tag(首页通常设置为true,不可关闭)
keepAlive: true // 是否需要缓存
}
......@@ -49,4 +16,4 @@ const dataDecreeRoutes = [
]
export default dataDecreeRoutes
\ No newline at end of file
export default dataTechnologyFiguresRoutes
\ No newline at end of file
......@@ -355,6 +355,9 @@ import { ElMessage } from "element-plus";
import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
import SimplePagination from "@/components/SimplePagination.vue";
import CustomContainer from "@/components/Container/index.vue";
import { useGotoNewsDetail } from "@/router/modules/news";
const gotoNewsDetail = useGotoNewsDetail();
const router = useRouter();
......@@ -515,13 +518,15 @@ const getUSGovernmentLatestDynamicData = async () => {
const handleClickTitle = item => {
if (!item || !item.id) return;
// 打开新标签页
const { href } = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(href, "_blank");
// const { href } = router.resolve({
// path: "/newsAnalysis",
// query: {
// newsId: item.id
// }
// });
// window.open(href, "_blank");
gotoNewsDetail(item.id);
};
const timelineList = ref([]);
......
......@@ -300,6 +300,8 @@ import {
getThreeMonthSanctionProcess
} from "@/api/allGovernment.js";
import CalendarHeatmap from "./components/CalendarHeatmap.vue";
import { useGotoNewsDetail } from "@/router/modules/news";
const gotoNewsDetail = useGotoNewsDetail();
const router = useRouter();
const activeDate = inject("activeDate");
......@@ -501,13 +503,15 @@ const updateRankListByPage = () => {
const handleNewsClick = item => {
if (!item || !item.id) return;
// 打开新标签页
const { href } = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(href, "_blank");
// const { href } = router.resolve({
// path: "/newsAnalysis",
// query: {
// newsId: item.id
// }
// });
// window.open(href, "_blank");
gotoNewsDetail(item.id);
};
// 点击联合制裁项-如果是政令则跳转详情
......
......@@ -47,12 +47,8 @@
<!-- <div class="right-num" :class="{ click: currentAntiType === 'num' }">排华联盟数量</div> -->
<!-- <div class="right-num" :class="{ click: currentAntiType === 'active' }">排华联盟动态</div> -->
<button-list :list="buttonList" :active-id="activeButtonId" @click="setActiveButtonId"></button-list>
<el-select
v-model="selectedFieldForLatest"
@change="handleFieldChange"
placeholder="全部领域"
class="field-select"
>
<el-select v-model="selectedFieldForLatest" @change="handleFieldChange" placeholder="全部领域"
class="field-select">
<el-option v-for="item in fieldOptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
......@@ -69,22 +65,12 @@
<div class="right-num">参与排华联盟</div>
</div>
</div>
<div
class="item"
v-for="(item, index) in countList"
:key="index"
@click="handleCountryClick(item)"
:class="{ 'selected-country': currentSelectedCountry && currentSelectedCountry.name === item.name }"
>
<div class="item" v-for="(item, index) in countList" :key="index" @click="handleCountryClick(item)"
:class="{ 'selected-country': currentSelectedCountry && currentSelectedCountry.name === item.name }">
<div class="item-left">
<img :src="item.image" alt />
<el-tooltip
effect="dark"
:content="item.zhName"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<el-tooltip effect="dark" :content="item.zhName" popper-class="common-prompt-popper" placement="top"
:show-after="500">
<span>{{ item.zhName }}</span>
</el-tooltip>
</div>
......@@ -100,22 +86,12 @@
<div class="right-num">{{ unionDynamicCount }}条动态</div>
</div>
</div>
<div
class="item carousel-item"
v-for="(item, index) in carouselPageList"
:key="index"
<div class="item carousel-item" v-for="(item, index) in carouselPageList" :key="index"
@click="handleUnionItemClick(item)"
:class="{ 'selected-item': currentSelectedUnion && currentSelectedUnion.id === item.id }"
>
:class="{ 'selected-item': currentSelectedUnion && currentSelectedUnion.id === item.id }">
<div class="item-top">
<div class="top-img">
<img
:src="ele"
:class="{ img1: idx !== 0 }"
alt
v-for="(ele, idx) in item.imageList"
:key="idx"
/>
<img :src="ele" :class="{ img1: idx !== 0 }" alt v-for="(ele, idx) in item.imageList" :key="idx" />
</div>
<div class="top-num">{{ item.count }}</div>
</div>
......@@ -159,13 +135,8 @@
<img src="./assets/news.png" alt />
<span>排华联盟最新动态</span>
</div>
<el-select
v-model="selectUnion"
placeholder="全部排华联盟"
class="custom-select"
:style="{ width: '160px' }"
@change="handleUnionChange"
>
<el-select v-model="selectUnion" placeholder="全部排华联盟" class="custom-select" :style="{ width: '160px' }"
@change="handleUnionChange">
<el-option v-for="item in unionListOption" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
......@@ -175,13 +146,8 @@
<img :src="item.image || defaultImg" alt />
<span @click="handleClick(item)">{{ item.title }}</span>
</div>
<el-tooltip
effect="dark"
:content="item.content"
popper-class="common-prompt-popper"
placement="top"
:show-after="500"
>
<el-tooltip effect="dark" :content="item.content" popper-class="common-prompt-popper" placement="top"
:show-after="500">
<template #content>
<div class="item-tooltip">
{{ item.content }}
......@@ -201,12 +167,8 @@
</div>
</div>
</div>
<simple-pagination
v-model:current-page="newsCurrentPage"
:page-size="newsPageSize"
:total="allNewsList.length"
@page-change="handleUnionPageChange"
/>
<simple-pagination v-model:current-page="newsCurrentPage" :page-size="newsPageSize" :total="allNewsList.length"
@page-change="handleUnionPageChange" />
</div>
<div class="warning">
<div class="warning-title">
......@@ -218,26 +180,16 @@
<div class="item-title">
<div class="title-left">
<div class="img-list">
<img
:src="ele.image || defaultImg"
:class="{ img1: index !== 0 }"
@error="e => (e.target.src = defaultImg)"
alt
v-for="(ele, index) in item.countryList"
:key="index"
/>
<img :src="ele.image || defaultImg" :class="{ img1: index !== 0 }"
@error="e => (e.target.src = defaultImg)" alt v-for="(ele, index) in item.countryList"
:key="index" />
</div>
<div class="left-content">{{ getContent(item.countryList) }}</div>
</div>
<div class="title-right">{{ item.statementList?.length }}次合作</div>
</div>
<div class="item-content">
<div
class="content-list"
v-for="(ele, idx) in item.statementList"
:key="idx"
@click="handleClick(ele)"
>
<div class="content-list" v-for="(ele, idx) in item.statementList" :key="idx" @click="handleClick(ele)">
<div class="list-left">
<!-- <span>{{ getName(ele.industryList) }}</span> -->
<AreaTag v-if="getName(ele.industryList)" :tagName="getName(ele.industryList)"></AreaTag>
......@@ -248,12 +200,8 @@
</div>
</div>
</div>
<simple-pagination
v-model:current-page="warningCurrentPage"
:page-size="warningPageSize"
:total="allWarningList.length"
@page-change="handleWarningPageChange"
/>
<simple-pagination v-model:current-page="warningCurrentPage" :page-size="warningPageSize"
:total="allWarningList.length" @page-change="handleWarningPageChange" />
</div>
</div>
......@@ -305,6 +253,9 @@ import { get, union, update } from "lodash";
import ButtonList from "@/components/buttonList/buttonList.vue";
import { fieldOptions, COLORS, countryNameMap, nameMap } from "@/views/ZMOverView/public.js";
import { countryCoordMap, convertAsiaCenterCoord } from "@/assets/json/countryCoordMap.js";
import { useGotoNewsDetail } from "@/router/modules/news";
const gotoNewsDetail = useGotoNewsDetail();
const buttonList = ref([
{
......@@ -1485,13 +1436,14 @@ const getDynamicList = async () => {
}
};
const handleClick = item => {
const { href } = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(href, "_blank");
// const { href } = router.resolve({
// path: "/newsAnalysis",
// query: {
// newsId: item.id
// }
// });
// window.open(href, "_blank");
gotoNewsDetail(item.id);
};
// 获取联盟预警
......@@ -1859,6 +1811,7 @@ watch(activeDate, async () => {
height: calc(100% - 48px);
display: flex;
justify-content: space-between;
.content-left {
width: 320px;
......@@ -1873,6 +1826,7 @@ watch(activeDate, async () => {
overflow: hidden;
border: 1px solid rgb(231, 243, 255);
border-radius: 10px;
// gap: 12px;
.count-box-header {
display: flex;
......@@ -1967,9 +1921,11 @@ watch(activeDate, async () => {
border-radius: 0px;
border-bottom: 1px solid rgb(231, 243, 255);
padding: 10px;
&.selected-item {
background-color: rgb(246, 250, 255) !important;
}
.item-top {
width: 100%;
height: 16px;
......@@ -2509,6 +2465,7 @@ watch(activeDate, async () => {
height: calc(100% - 80px);
padding: 33px 48px 40px 50px;
}
.anti-area-datasource {
text-align: center;
font-family: Source Han Sans CN;
......@@ -2518,6 +2475,7 @@ watch(activeDate, async () => {
align-items: center;
justify-content: center;
gap: 5px;
.tips-icon {
margin-top: 2px;
width: 16px;
......@@ -2567,6 +2525,7 @@ watch(activeDate, async () => {
height: 430px;
// padding: 33px 48px 59px 50px;
}
.anti-area-datasource {
text-align: center;
font-family: Source Han Sans CN;
......@@ -2576,6 +2535,7 @@ watch(activeDate, async () => {
align-items: center;
justify-content: center;
gap: 5px;
.tips-icon {
margin-top: 2px;
width: 16px;
......
......@@ -447,15 +447,12 @@ const handleToPage = async item => {
// break;
case "机构":
curRoute = router.resolve({
path: "/institution",
query: {
id: item.id
}
path: "/newsModeule/" + item.id
});
break;
case "新闻":
curRoute = router.resolve({
path: "/newsAnalysis",
name: "newsDetail",
query: {
newsId: item.id
}
......
......@@ -129,13 +129,13 @@ const handleToMoreNews = () => {
};
// 查看新闻资讯详情
const handleToNewsDetail = (item) => {
const route = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(route.href, "_blank");
// const route = router.resolve({
// path: "/newsAnalysis",
// query: {
// newsId: item.id
// }
// });
// window.open(route.href, "_blank");
}
// 查看社交媒体详情
const handleToSocialDetail = (item) => {
......
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_10" x1="12" x2="12" y1="4" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(114,46,209)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(114,46,209)" offset="1" stop-opacity="0.5" />
</linearGradient>
</defs>
<rect id="容器 1604" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="矢量 1680" d="M9.63557 4.71309L9.63557 4.71448C9.53504 4.71448 9.45369 4.6337 9.45369 4.53621L9.45369 4.35655C9.45404 4.16017 9.61674 4 9.81746 4L12.0001 4L14.1827 4C14.3837 4 14.5465 4.16017 14.5465 4.35655L14.5465 4.53482C14.5465 4.6337 14.4651 4.71309 14.3646 4.71309C14.264 4.71309 14.1827 4.79248 14.1827 4.89137L14.1827 8.45125C14.1827 8.51532 14.2001 8.57799 14.2335 8.63231L19.7952 17.8482C20.3689 18.798 19.6698 20 18.5429 20L5.45721 20C4.33038 20 3.63126 18.798 4.20498 17.8482L9.76666 8.63231C9.80005 8.57799 9.81746 8.51532 9.81746 8.45125L9.81746 4.89137C9.81746 4.79248 9.73611 4.71309 9.63557 4.71309ZM10.545 15.0529C10.545 14.4624 10.0565 13.9833 9.45369 13.9833C8.85084 13.9833 8.36238 14.4624 8.36238 15.0529C8.36238 15.6435 8.85084 16.1226 9.45369 16.1226C10.0565 16.1226 10.545 15.6435 10.545 15.0529ZM15.0921 14.6964C15.5944 14.6964 16.0015 15.0961 16.0015 15.5877C16.0015 16.0794 15.5944 16.4791 15.0921 16.4791C14.5898 16.4791 14.1827 16.0794 14.1827 15.5877C14.1827 15.0961 14.5898 14.6964 15.0921 14.6964ZM12.7276 17.5487C12.7276 17.1546 12.4018 16.8357 12.0001 16.8357C11.5983 16.8357 11.2725 17.1546 11.2725 17.5487C11.2725 17.9429 11.5983 18.2618 12.0001 18.2618C12.4018 18.2618 12.7276 17.9429 12.7276 17.5487Z" fill="url(#paint_linear_10)" fill-rule="evenodd" />
</svg>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_0" x1="12.5" x2="12.5" y1="5" y2="19.2500038" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(5,95,194)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(5,95,194)" offset="1" stop-opacity="0.5" />
</linearGradient>
</defs>
<rect id="容器 1604" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="合并" d="M19.625 7.375L19.625 6C19.625 5.44772 19.1773 5 18.625 5L4 5C3.44772 5 3 5.44772 3 6L3 18.0625C3 18.7186 3.53141 19.25 4.1875 19.25L20.2188 19.25C21.2026 19.25 22 18.4526 22 17.4688L22 8.375C22 7.82272 21.5523 7.375 21 7.375L19.625 7.375ZM17.5 8L5.5 8C5.22386 8 5 8.22386 5 8.5C5 8.77614 5.22386 9 5.5 9L17.5 9C17.7761 9 18 8.77614 18 8.5C18 8.22386 17.7761 8 17.5 8ZM6.00414 10L9.99929 10C10.5518 10 11.0005 10.4482 11 11.0007L10.995 16.0007C10.9946 16.5527 10.5477 17 9.99574 17L6.00071 17C5.44815 17 4.99961 16.5519 5 15.9993L5.00497 10.9992C5.00543 10.4472 5.45218 10 6.00414 10ZM17.498 10L12.502 10C12.2254 10 11.9978 10.2254 12 10.502L12.0041 10.502C12.0052 10.7774 12.2267 11 12.502 11L17.498 11C17.7749 11 18.0011 10.7749 18 10.498L17.9959 10.4979C17.9937 10.2223 17.7736 10 17.498 10ZM10 16L10 11L6 11L6 16L10 16ZM17.498 12L12.502 12C12.2254 12 11.9978 12.2254 12 12.502L12.0041 12.502C12.0052 12.7774 12.2267 13 12.502 13L17.498 13C17.7749 13 18.0011 12.7749 18 12.498L17.9959 12.4979C17.9937 12.2223 17.7736 12 17.498 12ZM17.498 14L12.502 14C12.2254 14 11.9978 14.2254 12 14.502L12.0041 14.502C12.0052 14.7774 12.2267 15 12.502 15L17.498 15C17.7749 15 18.0011 14.7749 18 14.498L17.9959 14.4979C17.9937 14.2223 17.7736 14 17.498 14ZM12.502 16L17.498 16C17.7736 16 17.9937 16.2223 17.9959 16.4979L18 16.498C18.0011 16.7749 17.7749 17 17.498 17L12.502 17C12.2267 17 12.0052 16.7774 12.0041 16.502L12 16.502C11.9978 16.2254 12.2254 16 12.502 16Z" fill="url(#paint_linear_0)" fill-rule="evenodd" />
</svg>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_1" x1="12" x2="12" y1="4" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(206,79,81)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(206,79,81)" offset="1" stop-opacity="0.5" />
</linearGradient>
</defs>
<rect id="容器 1605" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="矢量 347" d="M21.9043 19.0204L12.6181 4.32654C12.5871 4.27668 12.5495 4.2314 12.5053 4.1907C12.4611 4.15001 12.4118 4.11531 12.3575 4.08661C12.3032 4.05792 12.2457 4.03623 12.1851 4.02154C12.1244 4.00685 12.0627 3.99967 12 4.00001C11.759 4.00001 11.5181 4.10798 11.3819 4.32654L2.0957 19.0204C2.0801 19.0451 2.06633 19.0706 2.05439 19.097C2.04244 19.1234 2.03243 19.1503 2.02436 19.1779C2.01628 19.2054 2.0102 19.2333 2.00612 19.2616C2.00205 19.2899 2.00001 19.3183 2 19.3468C1.99999 19.3754 2.00203 19.4038 2.00609 19.432C2.01016 19.4603 2.01622 19.4882 2.02429 19.5158C2.03236 19.5434 2.04236 19.5703 2.05429 19.5967C2.06622 19.623 2.07999 19.6486 2.09558 19.6733C2.11117 19.698 2.12846 19.7217 2.14744 19.7443C2.16643 19.7669 2.18695 19.7883 2.209 19.8085C2.23106 19.8287 2.25446 19.8475 2.2792 19.8649C2.30395 19.8822 2.32983 19.8981 2.35684 19.9123C2.38385 19.9266 2.41177 19.9392 2.44059 19.9501C2.46941 19.9611 2.49889 19.9702 2.52902 19.9776C2.55916 19.985 2.58969 19.9906 2.62062 19.9944C2.65156 19.9981 2.68262 20 2.71383 20L21.2862 20C21.3174 20 21.3484 19.9981 21.3794 19.9944C21.4103 19.9906 21.4408 19.985 21.471 19.9776C21.5011 19.9702 21.5306 19.9611 21.5594 19.9501C21.5882 19.9392 21.6161 19.9266 21.6432 19.9123C21.6702 19.8981 21.6961 19.8822 21.7208 19.8649C21.7455 19.8475 21.7689 19.8287 21.791 19.8085C21.8131 19.7883 21.8336 19.7669 21.8526 19.7443C21.8715 19.7217 21.8888 19.698 21.9044 19.6733C21.92 19.6486 21.9338 19.623 21.9457 19.5967C21.9576 19.5703 21.9676 19.5434 21.9757 19.5158C21.9838 19.4882 21.9898 19.4603 21.9939 19.432C21.998 19.4038 22 19.3754 22 19.3468C22 19.3183 21.998 19.2899 21.9939 19.2616C21.9898 19.2333 21.9837 19.2054 21.9756 19.1779C21.9676 19.1503 21.9576 19.1234 21.9456 19.097C21.9337 19.0706 21.9199 19.0451 21.9043 19.0204ZM11.2857 10.0408C11.2857 9.95114 11.3662 9.87756 11.4643 9.87756L12.5357 9.87756C12.6338 9.87756 12.7143 9.95114 12.7143 10.0408L12.7143 13.7959C12.7143 13.8176 12.7097 13.8384 12.7006 13.8583C12.6915 13.8783 12.6786 13.8959 12.6619 13.9112C12.6451 13.9265 12.6259 13.9383 12.604 13.9466C12.5822 13.9549 12.5594 13.9591 12.5357 13.9592L11.4643 13.9592C11.4406 13.9591 11.4178 13.955 11.396 13.9466C11.3741 13.9383 11.3549 13.9265 11.3381 13.9112C11.3214 13.8959 11.3085 13.8783 11.2994 13.8583C11.2903 13.8384 11.2857 13.8176 11.2857 13.7959L11.2857 10.0408ZM12 17.2245C11.9296 17.2245 11.8599 17.2182 11.7909 17.2056C11.7219 17.1931 11.6549 17.1745 11.5899 17.1498C11.5249 17.1252 11.4631 17.095 11.4046 17.0592C11.3461 17.0235 11.292 16.9829 11.2422 16.9374C11.1925 16.8919 11.1481 16.8424 11.109 16.7889C11.0699 16.7354 11.0369 16.6789 11.01 16.6194C10.9831 16.56 10.9628 16.4987 10.9491 16.4356C10.9354 16.3725 10.9285 16.3088 10.9285 16.2445C10.9285 16.1801 10.9354 16.1164 10.9492 16.0533C10.9629 15.9902 10.9832 15.929 11.0102 15.8695C11.0371 15.8101 11.0702 15.7536 11.1093 15.7001C11.1484 15.6467 11.1928 15.5972 11.2426 15.5517C11.2924 15.5062 11.3465 15.4656 11.405 15.4299C11.4635 15.3941 11.5253 15.364 11.5903 15.3394C11.6553 15.3148 11.7224 15.2962 11.7914 15.2837C11.8604 15.2711 11.9301 15.2649 12.0005 15.2649C12.0708 15.2649 12.1405 15.2712 12.2096 15.2837C12.2786 15.2963 12.3456 15.3149 12.4106 15.3395C12.4756 15.3642 12.5373 15.3944 12.5959 15.4301C12.6544 15.4659 12.7085 15.5065 12.7582 15.552C12.808 15.5975 12.8524 15.647 12.8915 15.7005C12.9306 15.754 12.9636 15.8105 12.9905 15.8699C13.0174 15.9294 13.0377 15.9906 13.0514 16.0537C13.0651 16.1168 13.072 16.1806 13.072 16.2449C13.0719 16.3092 13.0651 16.3729 13.0513 16.436C13.0376 16.4991 13.0172 16.5604 12.9903 16.6198C12.9633 16.6793 12.9303 16.7357 12.8912 16.7892C12.8521 16.8427 12.8077 16.8922 12.7579 16.9377C12.7081 16.9831 12.654 17.0238 12.5955 17.0595C12.5369 17.0952 12.4752 17.1254 12.4101 17.15C12.3451 17.1746 12.2781 17.1932 12.2091 17.2057C12.1401 17.2182 12.0704 17.2245 12 17.2245Z" fill="url(#paint_linear_1)" fill-rule="nonzero" />
</svg>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_3" x1="12.2949219" x2="12.2949219" y1="4.5" y2="19.4999981" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(56,158,13)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(56,158,13)" offset="1" stop-opacity="0.5" />
</linearGradient>
</defs>
<rect id="容器 1600" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="合并" d="M5.23343 7.54601C5.23343 7.64577 5.23822 7.74529 5.24779 7.84457C5.25736 7.94385 5.27167 8.04241 5.29071 8.14026C5.30976 8.2381 5.33345 8.33475 5.3618 8.43022C5.39014 8.52569 5.42299 8.6195 5.46035 8.71167C5.49771 8.80383 5.53941 8.89391 5.58543 8.98189C5.61745 9.04311 5.65146 9.1031 5.68747 9.16188L5.68778 9.16239C5.70342 9.18792 5.71944 9.21322 5.73583 9.23828C5.79007 9.32123 5.84816 9.40126 5.9101 9.47838C5.97203 9.5555 6.03752 9.62932 6.10656 9.69987C6.17559 9.77041 6.24785 9.83732 6.32332 9.90061C6.39879 9.9639 6.47712 10.0233 6.55829 10.0787C6.63947 10.1341 6.72311 10.1853 6.80922 10.2324C6.89532 10.2794 6.98347 10.322 7.07368 10.3602C7.16388 10.3983 7.25569 10.4319 7.34912 10.4609C7.44255 10.4898 7.53714 10.514 7.6329 10.5335C7.72865 10.553 7.82511 10.5676 7.92228 10.5774C7.97291 10.5825 8.02361 10.5862 8.07438 10.5887C8.12102 10.5909 8.16772 10.592 8.21447 10.592C8.3121 10.592 8.4095 10.5871 8.50666 10.5774C8.60382 10.5676 8.70028 10.553 8.79604 10.5335C8.8918 10.514 8.98639 10.4898 9.07982 10.4609C9.17324 10.4319 9.26506 10.3983 9.35526 10.3602C9.44546 10.322 9.53361 10.2794 9.61972 10.2324C9.70582 10.1853 9.78946 10.1341 9.87064 10.0787C9.95182 10.0233 10.0301 9.9639 10.1056 9.90061C10.1811 9.83732 10.2533 9.77041 10.3224 9.69987C10.3914 9.62932 10.4569 9.5555 10.5188 9.47838C10.5808 9.40126 10.6389 9.32123 10.6931 9.23828C10.7473 9.15533 10.7975 9.06987 10.8435 8.98189C10.8895 8.89391 10.9312 8.80383 10.9686 8.71167C11.0059 8.6195 11.0388 8.52569 11.0671 8.43022C11.0955 8.33475 11.1192 8.2381 11.1382 8.14026C11.1465 8.09778 11.1539 8.05517 11.1604 8.01242L11.1604 8.01232C11.1688 7.95663 11.1757 7.90072 11.1811 7.84457C11.1907 7.74529 11.1955 7.64577 11.1955 7.54601C11.1955 7.44625 11.1907 7.34673 11.1811 7.24745C11.1716 7.14817 11.1573 7.04961 11.1382 6.95176C11.1192 6.85392 11.0955 6.75727 11.0671 6.6618C11.0388 6.56634 11.0059 6.47252 10.9686 6.38035C10.9312 6.28819 10.8895 6.19811 10.8435 6.11013C10.7975 6.02215 10.7473 5.93669 10.6931 5.85374C10.6389 5.77079 10.5808 5.69076 10.5188 5.61364C10.4569 5.53653 10.3914 5.4627 10.3224 5.39216C10.2533 5.32161 10.1811 5.2547 10.1056 5.19141C10.0301 5.12813 9.95182 5.06877 9.87064 5.01335C9.78946 4.95792 9.70582 4.9067 9.61972 4.85967C9.53361 4.81264 9.44546 4.77004 9.35526 4.73186C9.26506 4.69369 9.17324 4.66012 9.07982 4.63116C9.02364 4.61375 8.96704 4.59805 8.91002 4.58407L8.90992 4.58405L8.90984 4.58403C8.87209 4.57478 8.83416 4.56628 8.79604 4.55853C8.70028 4.53907 8.60382 4.52445 8.50666 4.51467C8.4095 4.50489 8.3121 4.5 8.21447 4.5C8.16774 4.5 8.12106 4.50112 8.07443 4.50336L8.07434 4.50337C8.02358 4.50581 7.9729 4.50957 7.92228 4.51467C7.82511 4.52445 7.72865 4.53907 7.6329 4.55853C7.59473 4.56628 7.55676 4.5748 7.51897 4.58406C7.46193 4.59804 7.40531 4.61374 7.34912 4.63116C7.25569 4.66012 7.16388 4.69369 7.07368 4.73186C7.04372 4.74454 7.01399 4.75771 6.98448 4.77136L6.98428 4.77146C6.92502 4.79889 6.86666 4.8283 6.80922 4.85967C6.78266 4.87417 6.75634 4.88908 6.73025 4.90438C6.67175 4.93869 6.61443 4.97502 6.55829 5.01335C6.47712 5.06877 6.39879 5.12813 6.32332 5.19141C6.30208 5.20922 6.28109 5.22732 6.26036 5.24571L6.26022 5.24584L6.2602 5.24586C6.20733 5.29275 6.15611 5.34152 6.10656 5.39216C6.03752 5.4627 5.97203 5.53653 5.9101 5.61364C5.89222 5.6359 5.87466 5.65841 5.85742 5.68116L5.85741 5.68117C5.81494 5.73721 5.77441 5.79474 5.73583 5.85374C5.68159 5.93669 5.63145 6.02215 5.58543 6.11013C5.57032 6.13901 5.55569 6.16811 5.54151 6.19744C5.5125 6.25746 5.48545 6.31844 5.46035 6.38035C5.44698 6.41335 5.43418 6.44655 5.42196 6.47997L5.42189 6.48015C5.40001 6.54002 5.37997 6.60057 5.3618 6.6618C5.35061 6.69947 5.34015 6.73732 5.33042 6.77535C5.31548 6.83372 5.30225 6.89252 5.29071 6.95176C5.27167 7.04961 5.25736 7.14817 5.24779 7.24745C5.23822 7.34673 5.23343 7.44625 5.23343 7.54601ZM13.8329 7.54601C13.8329 7.64577 13.8376 7.74529 13.8472 7.84457C13.8568 7.94385 13.8711 8.04241 13.8901 8.14026C13.9092 8.2381 13.9329 8.33475 13.9612 8.43022C13.9896 8.52569 14.0224 8.6195 14.0598 8.71167C14.0971 8.80383 14.1388 8.89391 14.1848 8.98189C14.2168 9.04305 14.2508 9.103 14.2868 9.16173L14.2869 9.16189L14.2879 9.16358C14.3033 9.18871 14.3191 9.21361 14.3352 9.23828C14.3895 9.32123 14.4476 9.40126 14.5095 9.47838C14.554 9.53378 14.6003 9.58749 14.6485 9.63949L14.6487 9.6397L14.6492 9.6402C14.6678 9.66034 14.6868 9.68023 14.706 9.69987C14.775 9.77041 14.8473 9.83732 14.9227 9.90061C14.9982 9.9639 15.0765 10.0233 15.1577 10.0787C15.2389 10.1341 15.3225 10.1853 15.4086 10.2324C15.4947 10.2794 15.5829 10.322 15.6731 10.3602C15.7633 10.3983 15.8551 10.4319 15.9485 10.4609C16.042 10.4898 16.1366 10.514 16.2323 10.5335C16.3281 10.553 16.4245 10.5676 16.5217 10.5774C16.6189 10.5871 16.7163 10.592 16.8139 10.592C16.9115 10.592 17.0089 10.5871 17.1061 10.5774C17.2032 10.5676 17.2997 10.553 17.3955 10.5335C17.4912 10.514 17.5858 10.4898 17.6792 10.4609C17.7727 10.4319 17.8645 10.3983 17.9547 10.3602C18.0449 10.322 18.133 10.2794 18.2191 10.2324C18.3052 10.1853 18.3889 10.1341 18.4701 10.0787C18.5512 10.0233 18.6296 9.9639 18.705 9.90061C18.7805 9.83732 18.8528 9.77041 18.9218 9.69987C18.9408 9.68046 18.9595 9.6608 18.978 9.64089L18.9791 9.6397L18.9792 9.63959C19.0274 9.58755 19.0737 9.53382 19.1183 9.47838C19.1802 9.40126 19.2383 9.32123 19.2925 9.23828C19.309 9.21311 19.3251 9.18771 19.3408 9.16208L19.3409 9.16192C19.3769 9.10313 19.4109 9.04312 19.4429 8.98189C19.4889 8.89391 19.5306 8.80383 19.568 8.71167C19.6054 8.6195 19.6382 8.52569 19.6666 8.43022C19.6777 8.39255 19.6882 8.35468 19.6979 8.31664C19.7129 8.25828 19.7261 8.19948 19.7376 8.14026C19.7567 8.04241 19.771 7.94385 19.7806 7.84457C19.7901 7.74529 19.7949 7.64577 19.7949 7.54601C19.7949 7.44625 19.7901 7.34673 19.7806 7.24745C19.771 7.14817 19.7567 7.04961 19.7376 6.95176C19.7186 6.85392 19.6949 6.75727 19.6666 6.6618C19.6382 6.56634 19.6054 6.47252 19.568 6.38035C19.5306 6.28819 19.4889 6.19811 19.4429 6.11013C19.4109 6.04888 19.3769 5.98886 19.3408 5.93005L19.3406 5.92964C19.3249 5.90411 19.3089 5.87881 19.2925 5.85374C19.2383 5.77079 19.1802 5.69076 19.1183 5.61364C19.0737 5.5582 19.0274 5.50446 18.9792 5.45241L18.9778 5.45097C18.9594 5.43112 18.9407 5.41151 18.9218 5.39216C18.8723 5.34161 18.8212 5.29293 18.7684 5.24611L18.7683 5.246C18.7475 5.22752 18.7264 5.20932 18.705 5.19141C18.6296 5.12813 18.5512 5.06877 18.4701 5.01335C18.4138 4.97497 18.3565 4.9386 18.2979 4.90425L18.2969 4.90365C18.2712 4.8886 18.2453 4.87394 18.2191 4.85967C18.133 4.81264 18.0449 4.77004 17.9547 4.73186C17.8645 4.69369 17.7727 4.66012 17.6792 4.63116C17.5858 4.6022 17.4912 4.57799 17.3955 4.55853C17.3416 4.54758 17.2875 4.53816 17.2332 4.53028C17.191 4.52415 17.1486 4.51894 17.1061 4.51467C17.0089 4.50489 16.9115 4.5 16.8139 4.5C16.7163 4.5 16.6189 4.50489 16.5217 4.51467C16.4245 4.52445 16.3281 4.53907 16.2323 4.55853C16.1366 4.57799 16.042 4.6022 15.9485 4.63116C15.8551 4.66012 15.7633 4.69369 15.6731 4.73186C15.5829 4.77004 15.4947 4.81264 15.4086 4.85967C15.3225 4.9067 15.2389 4.95792 15.1577 5.01335C15.0765 5.06877 14.9982 5.12813 14.9227 5.19141C14.8473 5.2547 14.775 5.32161 14.706 5.39216C14.6369 5.4627 14.5715 5.53653 14.5095 5.61364C14.4476 5.69076 14.3895 5.77079 14.3352 5.85374C14.281 5.93669 14.2309 6.02215 14.1848 6.11013C14.1388 6.19811 14.0971 6.28819 14.0598 6.38035C14.0224 6.47252 13.9896 6.56634 13.9612 6.6618C13.9329 6.75727 13.9092 6.85392 13.8901 6.95176C13.8711 7.04961 13.8568 7.14817 13.8472 7.24745C13.8376 7.34673 13.8329 7.44625 13.8329 7.54601ZM16.4518 11.1343C16.5423 11.1265 16.633 11.1229 16.7239 11.1235C16.8215 11.1235 16.9189 11.1284 17.0161 11.1381C17.1133 11.1479 17.2097 11.1625 17.3055 11.182C17.4012 11.2015 17.4958 11.2257 17.5893 11.2546C17.6827 11.2836 17.7745 11.3172 17.8647 11.3553C17.9549 11.3935 18.043 11.4361 18.1292 11.4831C18.2153 11.5302 18.2989 11.5814 18.3801 11.6368C18.4613 11.6922 18.5396 11.7516 18.6151 11.8149C18.6905 11.8782 18.7628 11.9451 18.8318 12.0156C18.9008 12.0862 18.9663 12.16 19.0283 12.2371C19.0902 12.3142 19.1483 12.3943 19.2025 12.4772C19.2568 12.5602 19.3069 12.6456 19.3529 12.7336C19.399 12.8216 19.4407 12.9117 19.478 13.0038C19.4914 13.0369 19.5043 13.0702 19.5165 13.1037C19.5384 13.1636 19.5584 13.2241 19.5766 13.2853C19.6049 13.3807 19.6286 13.4774 19.6477 13.5752C19.6667 13.6731 19.681 13.7716 19.6906 13.8709C19.7002 13.9702 19.7049 14.0697 19.7049 14.1695L19.7054 19.5L13.7433 19.5L13.7429 16.0123L12.774 16.9947C12.7395 17.0298 12.7019 17.0611 12.6613 17.0887C12.6207 17.1163 12.5779 17.1396 12.5328 17.1586C12.4877 17.1776 12.4413 17.1919 12.3935 17.2016C12.3457 17.2113 12.2974 17.2161 12.2486 17.2161C12.1999 17.2161 12.1516 17.2113 12.1038 17.2016C12.056 17.1919 12.0095 17.1776 11.9645 17.1586C11.9194 17.1396 11.8766 17.1163 11.836 17.0887C11.7954 17.0611 11.7578 17.0298 11.7232 16.9947L10.7618 16.0123L10.7623 19.5L4.80024 19.5L4.79976 14.1695C4.7942 14.0697 4.79343 13.97 4.79746 13.8702C4.80148 13.7704 4.81029 13.671 4.82386 13.5721C4.83744 13.4731 4.85573 13.3751 4.87873 13.278C4.90173 13.1809 4.92933 13.0852 4.96153 12.9909C4.99373 12.8966 5.03037 12.8041 5.07146 12.7135C5.11255 12.6228 5.15789 12.5345 5.20747 12.4484C5.24232 12.3879 5.27915 12.3287 5.31795 12.2708C5.33437 12.2464 5.35113 12.2222 5.36825 12.1982C5.42586 12.1174 5.48719 12.0398 5.55225 11.9653C5.61732 11.8907 5.6858 11.8196 5.7577 11.7519C5.8296 11.6842 5.90458 11.6203 5.98262 11.5601C6.06067 11.5 6.14141 11.4439 6.22485 11.3918C6.28179 11.3563 6.3398 11.3228 6.39888 11.2912C6.42638 11.2766 6.4541 11.2623 6.48206 11.2485C6.57009 11.2051 6.65999 11.1661 6.75176 11.1317C6.84353 11.0973 6.93674 11.0675 7.03137 11.0425C7.12601 11.0174 7.22161 10.9971 7.3182 10.9816C7.37087 10.9732 7.4237 10.9662 7.47668 10.9606C7.52084 10.956 7.5651 10.9524 7.60947 10.9498C7.70708 10.9441 7.80472 10.9432 7.9024 10.9473C8.00008 10.9514 8.09733 10.9603 8.19416 10.9741C8.29098 10.988 8.38691 11.0066 8.48194 11.0301C8.57697 11.0535 8.67064 11.0817 8.76297 11.1145C8.85529 11.1474 8.94582 11.1848 9.03455 11.2267C9.12328 11.2687 9.20978 11.3149 9.29406 11.3656C9.37834 11.4162 9.45999 11.4709 9.53901 11.5297C9.61803 11.5885 9.69404 11.6512 9.76704 11.7176C9.84004 11.7841 9.90968 11.854 9.97596 11.9274C10.0422 12.0009 10.1048 12.0775 10.1637 12.1572C10.2227 12.2369 10.2776 12.3194 10.3286 12.4046C10.3796 12.4898 10.4264 12.5774 10.4689 12.6673C10.5115 12.7573 10.5496 12.8491 10.5834 12.9429C10.6171 13.0366 10.6463 13.1318 10.6709 13.2285C10.6955 13.3252 10.7154 13.4229 10.7305 13.5216C10.7457 13.6203 10.7562 13.7195 10.7618 13.8192L12.2524 15.3422L13.7429 13.8192C13.7533 13.7269 13.7679 13.6354 13.7865 13.5445C13.8051 13.4536 13.8278 13.3638 13.8545 13.2751C13.8812 13.1863 13.9118 13.099 13.9463 13.0131C13.9808 12.9272 14.019 12.843 14.061 12.7607C14.1031 12.6784 14.1487 12.5982 14.1979 12.5201C14.2471 12.4421 14.2997 12.3665 14.3557 12.2933C14.3967 12.2397 14.4394 12.1875 14.4838 12.1369C14.5 12.1184 14.5164 12.1002 14.533 12.0821C14.5953 12.0145 14.6604 11.9499 14.7285 11.8884C14.7965 11.8269 14.8672 11.7686 14.9405 11.7137C15.0137 11.6588 15.0893 11.6073 15.1672 11.5595C15.245 11.5116 15.3249 11.4675 15.4067 11.427C15.4885 11.3866 15.5719 11.3501 15.657 11.3175C15.7421 11.2849 15.8285 11.2563 15.9161 11.2318C16.0037 11.2072 16.0923 11.1868 16.1818 11.1705C16.2712 11.1543 16.3612 11.1422 16.4518 11.1343Z" fill="url(#paint_linear_3)" fill-rule="evenodd" />
</svg>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_6" x1="13" x2="13" y1="4" y2="20" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(212,56,13)" offset="0" stop-opacity="1" />
<stop stop-color="rgb(212,56,13)" offset="1" stop-opacity="0.5" />
</linearGradient>
</defs>
<rect id="容器 1601" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
<path id="矢量 1679" d="M17 4C18.0195 4 18.8462 4.81132 18.8462 5.81132L18.8462 11.3443C18.2323 11.0861 17.5562 10.9434 16.8462 10.9434C14.0424 10.9434 11.7692 13.1733 11.7692 15.9245C11.7692 17.6097 12.6217 19.0991 13.9264 20L6.84615 20C5.82662 20 5 19.1887 5 18.1887L5 5.81132C5 4.81132 5.82662 4 6.84615 4L17 4ZM15.7692 6.71698C16.1091 6.71698 16.3846 6.98703 16.3846 7.32076C16.3846 7.65448 16.1091 7.92453 15.7692 7.92453L8.07692 7.92453C7.73708 7.92453 7.46154 7.65448 7.46154 7.32076C7.46154 6.98703 7.73708 6.71698 8.07692 6.71698L15.7692 6.71698ZM12.6923 9.73585C13.0322 9.73585 13.3077 10.0059 13.3077 10.3396C13.3077 10.6733 13.0322 10.9434 12.6923 10.9434L8.07692 10.9434C7.73708 10.9434 7.46154 10.6733 7.46154 10.3396C7.46154 10.0059 7.73708 9.73585 8.07692 9.73585L12.6923 9.73585ZM21 15.9245C21 13.6733 19.1403 11.8491 16.8462 11.8491C14.552 11.8491 12.6923 13.6733 12.6923 15.9245C12.6923 18.1757 14.552 20 16.8462 20C19.1403 20 21 18.1757 21 15.9245ZM10.8462 13.3585C10.8462 13.0248 10.5706 12.7547 10.2308 12.7547L8.07692 12.7547C7.73708 12.7547 7.46154 13.0248 7.46154 13.3585C7.46154 13.6922 7.73708 13.9623 8.07692 13.9623L10.2308 13.9623C10.5706 13.9623 10.8462 13.6922 10.8462 13.3585ZM16.8462 13.0566C17.4378 13.0566 17.9886 13.2288 18.4486 13.5259L14.4011 17.4965C14.0989 17.0448 13.9231 16.5047 13.9231 15.9245C13.9231 14.3408 15.2317 13.0566 16.8462 13.0566ZM16.8462 18.7925C16.2689 18.7925 15.7305 18.6285 15.2773 18.3443L19.3131 14.3856C19.6019 14.8302 19.7692 15.3585 19.7692 15.9245C19.7692 17.5083 18.4606 18.7925 16.8462 18.7925Z" fill="url(#paint_linear_6)" fill-rule="evenodd" />
</svg>
<template>
<div class="countrybill-wrapper">
<div class="header-box">
<div class="header-top">
<SelectBox :placeholder-name="areaPlaceHolder" select-title="科技领域" :select-list="areaList"
:select-name="selectedArea" @update:select-text="handleSelectArea" />
<SelectBox :placeholder-name="DatePlaceHolder" select-title="成立时间" :select-list="dateList"
:select-name="selectedDate" :custom-time="customTime" @update:select-text="handleSelectDate"
@update:custom-time="handleCustomDate" />
<SelectBox v-if="isFolderAll" :placeholder-name="countryPlaceHolder" select-title="国家地区"
:select-list="countryList" :select-name="selectedCountry" @update:select-text="handleSelectCountry" />
<SelectBox v-if="isFolderAll" :placeholder-name="companyTypePlaceHolder" select-title="企业类型"
:select-list="companyTypeList" :select-name="selectedCompanyType"
@update:select-text="handleSelectCompanyType" />
<div class="check-box">
<div class="check-box-left text-tip-1">
{{ '是否被制裁' }}
</div>
<div class="check-box-right">
<el-checkbox v-model="isSanctioned" class="involve-checkbox">
{{ '只看被制裁' }}
</el-checkbox>
</div>
</div>
</div>
<div class="header-footer">
<div class="header-footer-left">
<ActiveTag v-for="tag, index in activeTagList" :key="index" :tagName="tag.name"
@close="handleCloseCurTag(tag, index)" />
</div>
<div class="header-footer-right">
<HeaderBtnBox :isShowAll="isFolderAll" @show-all="handleSwitchFolderAll" @clear="handleClear"
@confirm="handleConfirm" />
</div>
</div>
</div>
<div class="chart-main-box" v-if="isShowChart">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box">
<div class="content-header">
<ChartHeader :list="staticsDemensionList" @clickItem="handleClickDemensionItem">
<template #chart-header-right>
<el-select v-model="selectedTime" placeholder="选择时间" style="width: 150px" v-show="curDemension === '成立时间'"
@change="handleChangeTime">
<el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</ChartHeader>
</div>
<div class="content-main">
<ChartContainer :chartTitle="curChartTitle" :chartTypeList="curChartTypeList"
@clickChartItem="handleSwitchActiveChart" @download="handleDownloadCurChartData">
<template #chart-box>
<LineChart v-if="activeChart === '折线图'" :lineChartData="curChartData" />
<BarChart v-if="activeChart === '柱状图'" :barChartData="curChartData" />
<PieChart v-if="activeChart === '饼状图'" :pieChartData="curChartData" />
<RaderChart v-if="activeChart === '雷达图'" :radarChartData="curChartData" />
</template>
</ChartContainer>
</div>
</div>
</div>
<div class="data-main-box" v-else>
<div class="data-main-box-header">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="data-main-box-main">
<div class="data-main-box-main-header">
<div class="header-left">
<div class="header-left-item1">
<el-checkbox v-model="isSelectedAll" label="全选" @change="handleSelectAllChange" size="large" />
</div>
<div class="header-left-item2 text-tip-1">{{ `已选择${selectedCount}项` }}</div>
<div class="header-left-item2 text-tip-1 cancel" @click="handleClearAll" v-show="selectedCount">{{ '取消' }}
<div class="header-left-item3 text-tip-1" v-if="isShowAllDataMaxLengthTip">{{ `(当前最大选择不能超过1万条!)` }}</div>
</div>
</div>
<div class="header-right">
<div class="header-right-item item1" @click="handleExport">
<div class="icon">
<img src="../assets/icons/download.svg" alt="">
</div>
<div class="text text-tip-1">{{ '导出' }}</div>
</div>
<div class="header-right-item2 item2">
<el-select v-model="curOperation" placeholder="批量操作" style="width: 120px">
<el-option v-for="item in operationList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div class="header-right-item3 item3">
<el-select v-model="isSort" placeholder="成立时间" style="width: 166px" @change="handlePxChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img src="../assets/icons/desc-icon.svg" style="width: 14px; height: 14px" />
</div>
</template>
<el-option v-for="item in releaseTimeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
</div>
<div class="data-main-box-main-content" v-loading="loading" element-loading-text="数据加载中,请稍候...">
<el-table ref="tableRef" :data="tableData" row-key="id" @selection-change="handleSelectionChange"
@select="handleSelect" @select-all="handleSelectAll" style="width: 100%" :row-style="{ height: '52px' }">
<el-table-column type="selection" width="40" />
<el-table-column label="企业名称" width="600">
<template #default="scope">
<span class="title-item text-compact-bold" @click="handleClickToDetail(scope.row)">{{
scope.row.originalTitle
}}</span>
</template>
</el-table-column>
<el-table-column label="成立时间" width="120" class-name="date-column">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column label="国家地区">
<template #default="scope">
<span class="person-item text-compact" @click="handleOrgClick(scope.row)">{{ scope.row.organizationName
}}</span>
</template>
</el-table-column>
<el-table-column label="涉及领域" width="350" class-name="date-column">
<template #default="scope">
<div class="tag-box">
<AreaTag v-for="tag, index in scope.row.domains" :key="index" :tagName="tag" />
</div>
</template>
</el-table-column>
<el-table-column label="企业类型" width="100">
<template #default="scope">{{ scope.row.typeStr }}</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="data-main-box-footer">
<el-pagination background layout="prev, pager, next" :total="totalNum" v-model:current-page="currentPage"
:page-size="pageSize" @current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import ChartContainer from '../components/ChartContainer/index.vue'
import ChartHeader from '../components/ChartHeader/index.vue'
import ActiveTag from '../components/ActiveTag/index.vue'
import HeaderBtnBox from '../components/HeaderBtnBox/index.vue'
import LineChart from '../components/LineChart/index.vue'
import PieChart from '../components/PieChart/index.vue'
import BarChart from '../components/BarChart/index.vue'
import RaderChart from '../components/RadarChart/idnex.vue'
import SelectBox from '../components/SelectBox/index.vue'
import { useRoute } from "vue-router";
import router from '@/router'
import { search } from '@/api/comprehensiveSearch'
import { ElMessage } from 'element-plus'
import getDateRange from '@/utils/getDateRange'
import { getCountryList, getBusinessType } from '@/api/comprehensiveSearch/index'
const route = useRoute();
// 图表/数据
const isShowChart = ref(false)
// 点击切换数据/图表
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
if (isShowChart.value) {
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
// setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
if (curDemension.value === '成立时间') {
if (selectedTime.value === '按月度统计') {
curChartData.value = curDemensionItem.data
} else if (selectedTime.value === '按季度统计') {
curChartData.value = curDemensionItem.quatarData
} else {
curChartData.value = curDemensionItem.yearData
}
} else {
curChartData.value = curDemensionItem.data
}
// })
}
}
// 总计数据
const totalNum = ref(0)
// 统计维度列表
const staticsDemensionList = ref([
{
name: '成立时间',
active: true,
chartTypeList: ['折线图', '柱状图'],
chartTitle: '科技企业成立数量随时间变化趋势',
data: {
dataX: [],
dataY: []
},
quatarData: {
dataX: [],
dataY: []
},
yearData: {
dataX: [],
dataY: []
}
},
{
name: '科技领域',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '科技企业领域分布',
data: []
},
{
name: '国家地区',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '科技企业国家地区分布',
data: []
}
])
// 当前维度下的图表列表
const curChartTypeList = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTypeList
})
// 当前图表标题
const curChartTitle = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTitle
})
// 当前维度
const curDemension = ref('成立时间')
// 点击维度item
const handleClickDemensionItem = (val) => {
activeChart.value = ''
staticsDemensionList.value.forEach(item => {
item.active = false
})
val.active = true
curDemension.value = val.name
setTimeout(() => {
activeChart.value = val.chartTypeList[0]
if (curDemension.value === '成立时间' && selectedTime.value === '按年度统计') {
curChartData.value = val.yearData
} else if (curDemension.value === '成立时间' && selectedTime.value === '按季度统计') {
curChartData.value = val.quatarData
} else {
curChartData.value = val.data
}
})
}
// 时间图表 当前选择时间
const selectedTime = ref('按年度统计')
// 时间图表-时间列表
const timeList = ref([
{
label: '按年度统计',
value: '按年度统计'
},
{
label: '按季度统计',
value: '按季度统计'
},
{
label: '按月度统计',
value: '按月度统计'
},
])
const handleChangeTime = value => {
let curChart = activeChart.value
activeChart.value = ''
if (value === '按月度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].data
})
} else if (value === '按季度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].quatarData
})
} else {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].yearData
})
}
}
// 激活的标签列表
const activeTagList = computed(() => {
const arr = []
if (selectedArea.value && selectedArea.value !== '全部领域') {
arr.push(
{
tag: '科技领域',
name: selectedArea.value
}
)
}
if (selectedDate.value === '自定义') {
arr.push(
{
tag: '成立时间',
name: customTime.value.join('至')
}
)
}
if (selectedCountry.value && selectedCountry.value !== '全部国家地区') {
let countryStr = countryList.value.filter(item => item.id === selectedCountry.value)[0].name
arr.push(
{
tag: '国家地区',
name: countryStr
}
)
}
if (selectedCompanyType.value && selectedCompanyType.value !== '全部类型') {
arr.push(
{
tag: '企业类型',
name: selectedCompanyType.value
}
)
}
if (isSanctioned.value) {
const santionStr = '被制裁'
arr.push(
{
tag: '是否被制裁',
name: santionStr
}
)
}
return arr
})
// 关闭当前标签
const handleCloseCurTag = (tag, index) => {
switch (tag.tag) {
case '科技领域':
selectedArea.value = '全部领域'
break
case '成立时间':
selectedDate.value = ''
customTime.value = []
break
case '国家地区':
selectedCountry.value = '全部国家地区'
break
case '企业类型':
selectedCompanyType.value = '全部类型'
break
case '是否被制裁':
isSanctioned.value = false
break
}
// alert(tag.name)
// activeTagList.value.splice(index, 1)
}
const activeChart = ref('') // 当前激活的图表
// 切换当前图表
const handleSwitchActiveChart = val => {
activeChart.value = val.name
}
// 雷达图数据
const radarChartData = ref({
title: [
{
name: '航空航天',
max: 10
},
{
name: '先进制造',
max: 10
},
{
name: '量子科技',
max: 10
},
{
name: '人工智能',
max: 10
},
{
name: '新材料',
max: 10
},
{
name: '集成电路',
max: 10
},
],
data: [
{
name: "337调查",
value: [10, 5, 2, 8, 5, 7
]
},
{
name: "232调查",
value: [2, 5, 3, 8, 10, 2]
},
{
name: "301调查",
value: [5, 8, 2, 9, 1, 5]
}
]
}
)
// 数据- 是否全选
const isSelectedAll = ref(false)
// 批量操作-当前操作
const curOperation = ref('')
const operationList = ref([
{
name: 'aaa',
id: 'aaa'
},
{
name: 'bbb',
id: 'bbb'
},
{
name: 'ccc',
id: 'ccc'
},
])
// 科技领域
const areaPlaceHolder = ref('请选择领域')
const selectedArea = ref('全部领域')
const areaList = ref([
{
name: '全部领域',
id: '全部领域'
},
{
name: '人工智能',
id: '人工智能'
},
{
name: '生物科技',
id: '生物科技'
},
{
name: '新一代通信网络',
id: '新一代通信网络'
},
{
name: '量子科技',
id: '量子科技'
},
{
name: '新能源',
id: '新能源'
},
{
name: '集成电路',
id: '集成电路'
},
{
name: '海洋',
id: '海洋'
},
{
name: '先进制造',
id: '先进制造'
},
{
name: '新材料',
id: '新材料'
},
{
name: '航空航天',
id: '航空航天'
},
{
name: '太空',
id: '太空'
},
{
name: '深海',
id: '深海'
},
{
name: '极地',
id: '极地'
},
{
name: '核',
id: '核'
},
{
name: '其他',
id: '其他'
},
])
const handleSelectArea = (value) => {
selectedArea.value = value
}
// 提出时间
const DatePlaceHolder = ref('请选择时间')
const selectedDate = ref('')
const dateList = ref([
{
name: '自定义',
id: '自定义'
},
{
name: '近一年',
id: '近一年'
},
{
name: '近半年',
id: '近半年'
},
{
name: '近三月',
id: '近三月'
},
{
name: '近一月',
id: '近一月'
}
])
const customTime = ref([]) // 自定义时间
const handleCustomDate = value => {
customTime.value = value
}
const handleSelectDate = (value) => {
selectedDate.value = value
if (selectedDate.value !== '自定义') {
customTime.value = getDateRange(selectedDate.value)
}
}
// 国家地区
const countryList = ref([
{
name: '全部国家地区',
id: '全部国家地区'
},
])
const selectedCountry = ref('全部国家地区')
const countryPlaceHolder = ref('请选择国家地区')
const handleSelectCountry = value => {
selectedCountry.value = value
}
const handleGetCountryList = async () => {
try {
const res = await getCountryList();
console.log("国家列表", res);
if (res.code === 200) {
let arr = res.data.map(item => {
return {
name: item.name,
id: item.id
}
})
countryList.value = [...countryList.value, ...arr]
}
} catch (error) {
}
}
// 企业类型列表
const companyTypeList = ref([
{
name: '全部类型',
id: '全部类型'
},
])
const selectedCompanyType = ref('全部类型')
const companyTypePlaceHolder = ref('请选择企业类型')
const handleSelectCompanyType = value => {
selectedCompanyType.value = value
}
// 获取企业类型
const handleGetCompanyType = async () => {
try {
const res = await getBusinessType()
console.log('企业类型', res);
if(res && res.length) {
let arr = res.map(item => {
return {
name: item,
id: item
}
})
companyTypeList.value = [...arr,...companyTypeList.value]
}
} catch (error) {
console.error('获取企业类型error', error);
}
}
// 是否被制裁
const isSanctioned = ref(false)
// 清空条件
const handleClear = () => {
selectedArea.value = '全部领域'
selectedDate.value = ''
customTime.value = []
selectedCountry.value = '全部国家地区'
selectedCompanyType.value = '全部类型'
isSanctioned.value = false
ElMessage.success('已清空条件!')
}
// 确定
const handleConfirm = () => {
currentPage.value = 1
fetchTableData()
}
// 展开全部 / 收起
const isFolderAll = ref(false)
const handleSwitchFolderAll = () => {
isFolderAll.value = !isFolderAll.value
}
const tableRef = ref(null)
// 表格数据
const tableData = ref([
])
const releaseTimeList = ref([
{
label: "按成立时间倒序",
value: true
},
{
label: "按成立时间升序",
value: false
}
]);
const isSort = ref(true); // true 倒序 false 升序
const handlePxChange = val => {
fetchTableData()
};
const currentPage = ref(1);
const pageSize = ref(10)
// 存储选中的数据(跨页)[citation:3][citation:8]
const selectedMap = ref(new Map()) // 使用 Map 存储,key 为唯一 id
// 计算已选中的条数
const selectedCount = computed(() => selectedMap.value.size)
// 获取当前页表格数据(示例)
const fetchTableData = async () => {
loading.value = true
// 调用接口获取数据...
const params = {
page: currentPage.value,
size: pageSize.value,
type: 5, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
domains: selectedArea.value === '全部领域' ? null : [selectedArea.value],
proposedDateStart: customTime.value[0] ? customTime.value[0] : null,
proposedDateEnd: customTime.value[1] ? customTime.value[1] : null,
countryId: selectedCountry.value === '全部国家地区' ? null : selectedCountry.value,
businessType: selectedCompanyType.value === '全部类型' ? null : selectedCompanyType.value,
isSanctioned: isSanctioned.value ? 'Y' : null,
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
tableData.value = res.data.records
totalNum.value = res.data.total
staticsDemensionList.value[0].data = {
dataX: Object.keys(res.data.aggregationsDate),
dataY: Object.values(res.data.aggregationsDate).map(value => Number(value))
}
staticsDemensionList.value[0].quatarData = {
dataX: Object.keys(res.data.aggregationsQuarter),
dataY: Object.values(res.data.aggregationsQuarter).map(value => Number(value))
}
staticsDemensionList.value[0].yearData = {
dataX: Object.keys(res.data.aggregationsYear),
dataY: Object.values(res.data.aggregationsYear).map(value => Number(value))
}
staticsDemensionList.value[1].data = Object.entries(res.data.aggregationsDomain).map(([key, value]) => ({
name: key,
value: Number(value)
}))
staticsDemensionList.value[2].data = Object.entries(res.data.aggregationCountryId).map(([key, value]) => ({
name: key,
value: Number(value)
}))
}
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
activeChart.value = ''
setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
curChartData.value = curDemensionItem.data
})
} catch (error) {
console.error(error);
} finally {
loading.value = false
}
// 数据加载后,回显已选中的行
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
}
const allData = ref([])
// 获取筛选条件下全部表格数据
const fetchAllData = async () => {
const params = {
page: 1,
size: 9999,
type: 5, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
domains: selectedArea.value === '全部领域' ? null : [selectedArea.value],
proposedDateStart: customTime.value[0] ? customTime.value[0] : null,
proposedDateEnd: customTime.value[1] ? customTime.value[1] : null,
countryId: selectedCountry.value === '全部国家地区' ? null : selectedCountry.value,
businessType: selectedCompanyType.value === '全部类型' ? null : selectedCompanyType.value,
isSanctioned: isSanctioned.value ? 'Y' : null,
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
allData.value = res.data.records
}
} catch (error) {
ElMessage.error('加载全部数据出错!')
}
}
// 单选事件
const handleSelect = (selection, row) => {
if (selection.some(item => item.id === row.id)) {
// 选中:添加到 Map
selectedMap.value.set(row.id, row)
} else {
// 取消选中:从 Map 移除
selectedMap.value.delete(row.id)
}
}
// 表格自带 当前页 全选/全不选事件
const handleSelectAll = (selection) => {
if (selection.length > 0) {
// 全选:将当前页所有数据添加到 Map
tableData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
} else {
// 全不选:从 Map 中移除当前页的所有数据
tableData.value.forEach(row => {
selectedMap.value.delete(row.id)
})
}
}
// 处理选择变化(用于统计)
const handleSelectionChange = (val) => {
// 这里可以做一些额外的处理,但主要统计使用 selectedMap
console.log('当前页选中数量:', val.length)
}
// 全选当前页按钮
const handleSelectAllPage = () => {
if (tableData.value.length === 0) return
// 检查当前页是否已全选
const currentPageSelected = tableData.value.every(row =>
selectedMap.value.has(row.id)
)
if (currentPageSelected) {
// 已全选,则不动当前页的全选
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, false)
// selectedMap.value.delete(row.id)
})
} else {
// 未全选,则全选当前页
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, true)
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
}
}
// 全选最大1万条提示
const isShowAllDataMaxLengthTip = ref(false)
const loading = ref(false) // 加载数据loading
// 处理 全选(全部数据)
const handleSelectAllChange = async () => {
if (isSelectedAll.value) {
if (totalNum.value > 10000) {
isShowAllDataMaxLengthTip.value = true
}
loading.value = true
await fetchAllData()
handleSelectAllPage()
allData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
loading.value = false
} else {
handleClearAll()
}
}
// 清空所有选择
const handleClearAll = () => {
isSelectedAll.value = false
selectedMap.value.clear()
tableRef.value?.clearSelection()
}
// 翻页
const handleCurrentChange = async (val) => {
currentPage.value = val
await fetchTableData()
if (isSelectedAll.value) {
handleSelectAllPage()
}
}
// 监听数据变化,回显选中状态 [citation:4][citation:8]
watch(tableData, () => {
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
})
// 当前图表数据
const curChartData = ref(null)
// 下载当前图表数据
const handleDownloadCurChartData = () => {
const jsonStr = JSON.stringify(curChartData.value, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'chartData.json';
link.click();
URL.revokeObjectURL(url);
}
// 跳转到当前页 初始化筛选条件
const initParam = () => {
const hasQuery = Object.keys(route.query).length > 0;
if (hasQuery) {
selectedArea.value = route.query.domains ? route.query.domains : '全部领域'
if (route.query.selectedDate && Array.isArray(JSON.parse(route.query.selectedDate)) && JSON.parse(route.query.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(route.query.selectedDate)
}
selectedCountry.value = route.query.orgnizationName ? route.query.orgnizationName : '全部国家地区'
isSanctioned.value = route.query.isSanctioned ? true : false
selectedCompanyType.value = route.query.selectedCompanyType ? route.query.selectedCompanyType : '全部类型'
const query = route.query;
if (Object.keys(query).length > 0) {
sessionStorage.setItem('decreeRouteQuery', JSON.stringify(query));
}
} else {
const savedQuery = JSON.parse(sessionStorage.getItem('decreeRouteQuery') || '{}');
selectedArea.value = savedQuery.domains ? savedQuery.domains : '全部领域'
if (savedQuery.selectedDate && Array.isArray(JSON.parse(savedQuery.selectedDate)) && JSON.parse(savedQuery.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(savedQuery.selectedDate)
}
isSanctioned.value = savedQuery.isSanctioned ? true : false
selectedCompanyType.value = savedQuery.selectedCompanyType ? savedQuery.selectedCompanyType : '全部类型'
}
}
// 跳转企业详情
const handleClickToDetail = (item) => {
console.log('item', item);
window.sessionStorage.setItem('curTabName', item.originalTitle)
const route = router.resolve({
name: "companyPages",
params: {
id: item.id
}
});
window.open(route.href, "_blank");
};
// 跳转机构详情
const handleOrgClick = item => {
console.log('item', item);
window.sessionStorage.setItem("curTabName", item.organizationName);
const route = router.resolve({
path: "/institution",
query: {
id: item.organizationId
}
});
window.open(route.href, "_blank");
};
// 导出
const handleExport = () => {
if (!selectedCount.value) {
ElMessage.warning('请选择至少一项数据!')
return
}
console.log(selectedMap.value);
const arr = Array.from(selectedMap.value);
const jsonStr = JSON.stringify(arr, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'export.json';
link.click();
URL.revokeObjectURL(url);
};
onMounted(async () => {
await handleGetCountryList()
await handleGetCompanyType()
initParam()
// 初始化
fetchTableData()
})
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
overflow: hidden;
overflow-y: auto;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
min-height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
box-sizing: border-box;
padding: 16px 24px;
.header-top {
min-height: 28px;
display: flex;
flex-wrap: wrap;
gap: 12px 42px;
// transition: all ease 1s;
.check-box {
display: flex;
width: 348px;
height: 28px;
align-items: center;
gap: 8px;
.check-box-left {
width: 100px;
color: var(--text-primary-65-color);
}
}
}
.header-footer {
margin-top: 16px;
display: flex;
justify-content: space-between;
.header-footer-left {
display: flex;
justify-content: space-between;
gap: 8px;
}
}
}
.chart-main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
.content-header {
margin: 16px 24px;
width: 1520px;
height: 28px;
}
.content-main {
width: 1520px;
margin: 0 auto;
}
}
}
.data-main-box {
width: 1568px;
min-height: 810px;
border-radius: 10px;
background: var(--bg-white-100);
margin: 0 auto;
margin-bottom: 20px;
overflow: hidden;
.data-main-box-header {
margin: 16px auto;
width: 1520px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
box-sizing: border-box;
padding: 2px 0;
color: var(--color-red-100);
}
}
.data-main-box-main {
width: 1520px;
// height: 633px;
min-height: 680px;
border-radius: 10px;
border: 1px solid var(--bg-black-5);
margin: 0 auto;
.data-main-box-main-header {
height: 48px;
background: var(--bg-black-2);
display: flex;
justify-content: space-between;
.header-left {
margin-left: 16px;
height: 48px;
display: flex;
gap: 16px;
align-items: center;
.header-left-item2 {
color: var(--color-primary-100);
display: flex;
gap: 8px;
}
.header-left-item3 {
color: var(--color-orange-100);
}
.cancel {
cursor: pointer;
}
}
.header-right {
margin-right: 16px;
display: flex;
gap: 8px;
align-items: center;
.header-right-item {
height: 30px;
padding: 5px 16px;
border: 1px solid var(--bg-black-10);
border-radius: 4px;
background: var(--bg-white-100);
cursor: pointer;
}
.item1 {
display: flex;
gap: 2px;
justify-content: center;
align-items: center;
&:hover {
background: var(--color-primary-2);
}
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
color: var(--text-primary-65-color);
}
}
.item2 {}
.item3 {}
}
}
.data-main-box-main-content {}
}
.data-main-box-footer {
margin: 16px auto 0;
height: 40px;
width: 1520px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
.date-column {
background-color: #ecf5ff;
.tag-box {
display: flex;
flex-wrap: wrap;
gap: 8px;
width: 340px;
}
}
.date-column .cell {
color: #409eff !important;
font-weight: 500;
}
.title-item {
color: var(--text-primary-80-color);
cursor: pointer;
&:hover {
color: var(--color-primary-100);
text-decoration: underline;
}
}
.person-item {
color: var(--color-primary-100);
cursor: pointer;
&:hover {
font-weight: bold;
text-decoration: underline;
}
}
:deep(.el-table__header-wrapper) {
// background-color: #f5f7fa;
height: 48px;
}
:deep(.el-table__header th) {
// background-color: #f5f7fa;
color: var(--text-primary-50-color);
font-weight: bold;
}
/* 针对特定列 */
// :deep(.el-table__header th:first-child) {
// background-color: #e6f7ff;
// color: #1890ff;
// }</style>
\ No newline at end of file
......@@ -71,8 +71,13 @@ const getBarChart = (data) => {
fontSize: 16,
fontFamily: 'Source Han Sans CN',
formatter: function (params) {
return params.value
},
// params.value 是当前数据项的值
if (params.value > 0) {
return params.value; // 值大于0时返回数值,显示标签
} else {
return ''; // 值等于0时返回空字符串,不显示标签
}
}
},
barWidth: data.dataX.length < 60 ? 20 : 3,
itemStyle: {
......
......@@ -13,14 +13,16 @@ const getPieChart = (data) => {
let option = {
color: colorList,
legend: {
show: false
show: true,
top: 12
},
series: [
{
type: 'pie',
radius: [160, 190],
height: '100%',
radius: [150, 180],
// height: '96%',
left: 'center',
top: 24,
width: '98%',
itemStyle: {
borderColor: '#fff',
......
......@@ -1082,18 +1082,18 @@ const initParam = () => {
}
// 跳转政令详情
const handleClickToDetail = (curDecree) => {
console.log('curDecree', curDecree);
// 跳转机构详情
const handleClickToDetail = (curEntity) => {
console.log('curEntity', curEntity);
window.sessionStorage.setItem("decreeId", curDecree.id);
window.sessionStorage.setItem("curTabName", curDecree.title);
window.sessionStorage.setItem("decreeId", curEntity.id);
window.sessionStorage.setItem("curTabName", curEntity.title);
const route = router.resolve({
path: "/decreeLayout",
query: {
id: curDecree.id
}
});
name: "companyPages",
params: {
id: curEntity.id
}
});
window.open(route.href, "_blank");
};
......
......@@ -819,19 +819,35 @@ const initParam = () => {
}
// 跳转政令详情
const handleClickToDetail = (curDecree) => {
console.log('curDecree', curDecree);
window.sessionStorage.setItem("decreeId", curDecree.id);
window.sessionStorage.setItem("curTabName", curDecree.title);
const route = router.resolve({
path: "/decreeLayout",
query: {
id: curDecree.id
}
});
window.open(route.href, "_blank");
// 跳转单次清单事件详情
const handleClickToDetail = (curEntityEvent) => {
console.log('curEntityEvent', curEntityEvent);
// window.sessionStorage.setItem("decreeId", curEntityEvent.id);
// window.sessionStorage.setItem("curTabName", curEntityEvent.title);
// let id = item?.id;
// let sanTypeId = item?.sanTypeId || 1;
// if (!id) {
// const currentItem = entitiesDataInfoList.value[currentCarouselIndex.value];
// id = currentItem?.id;
// sanTypeId = currentItem?.sanTypeId || 1;
// }
// window.sessionStorage.setItem(
// "curTabName",
// entitiesDataInfoList.value[currentCarouselIndex.value].postDate + " 《实体清单新增条目》"
// );
// let date = entitiesDataInfoList.value[currentCarouselIndex.value].postDate
// const routeData = router.resolve({
// path: "/exportControl/singleSanction",
// query: {
// id,
// sanTypeId,
// date
// }
// });
// // 打开一个新页面
// window.open(routeData.href, "_blank");
};
// 跳转机构详情
......
......@@ -77,13 +77,12 @@ import Icon1 from "./assets/icons/sider-icon1.svg";
import Icon2 from "./assets/icons/sider-icon2.svg";
import Icon3 from "./assets/icons/sider-icon3.svg";
import Icon4 from "./assets/icons/sider-icon4.svg";
import Icon5 from "./assets/icons/sider-icon5.svg";
import Icon6 from "./assets/icons/sider-icon6.svg";
import Icon7 from "./assets/icons/sider-icon7.svg";
import Icon8 from "./assets/icons/sider-icon8.svg";
import Icon9 from "./assets/icons/sider-icon9.svg";
import Icon10 from "./assets/icons/sider-icon10.svg";
import Icon11 from "./assets/icons/sider-icon11.svg";
import Icon12 from "./assets/icons/sider-icon12.svg";
import Icon13 from "./assets/icons/sider-icon13.svg";
import { useRouter, useRoute } from "vue-router";
import useTagsViewStore from "@/stores/tagsView.js";
......@@ -172,14 +171,6 @@ const siderList = ref([
}
]
},
// {
// name: '合作限制',
// icon: Icon5,
// active: false,
// isExpanded: false,
// children: [
// ]
// },
{
name: "投融资限制",
icon: Icon6,
......@@ -231,52 +222,23 @@ const siderList = ref([
}
]
},
// {
// name: '规则限制',
// icon: Icon8,
// active: false,
// isExpanded: false,
// children: [
// ]
// },
{
name: "美国科技人物观点",
name: "科技人物",
path: "/dataLibrary/dataTechnologyFigures",
icon: Icon9,
active: false,
isExpanded: false,
children: [
{
name: "国会议员",
path: "/dataLibrary/congressMan",
active: false
},
{
name: "科技企业领袖",
path: "/dataLibrary/technologyLeader",
active: false
},
{
name: "机构主官",
path: "/dataLibrary/minister",
active: false
},
{
name: "智库研究人员",
path: "/dataLibrary/thinkTankResearcher",
active: false
}
]
children: []
},
{
name: "美国主要创新主体",
name: "重要实体",
icon: Icon10,
active: false,
isExpanded: false,
children: [
{
name: "科技企业",
path: "/dataLibrary/technologyCompany",
path: "/dataLibrary/dataCompany",
active: false
},
{
......@@ -288,25 +250,30 @@ const siderList = ref([
name: "重点实验室",
path: "/dataLibrary/keyLab",
active: false
},
{
name: "政府机构",
path: "/dataLibrary/dataInstitution",
active: false
}
]
}
// {
// name: '美国科研资助体系',
// icon: Icon11,
// active: false,
// isExpanded: false,
// children: [
// {
// name: '美国科研资助体系1',
// active: false,
// },
// {
// name: '美国科研资助体系2',
// active: false,
// },
// ]
// },
},
{
name: "新闻",
path: "/dataLibrary/dataNews",
icon: Icon12,
active: false,
isExpanded: false,
children: []
},
{
name: "风险信号",
path: "/dataLibrary/dataRiskSignal",
icon: Icon13,
active: false,
isExpanded: false,
children: []
},
]);
const handleSiderItem = item => {
......@@ -545,27 +512,10 @@ onMounted(() => {
siderList.value[5].isExpanded = true;
siderList.value[5].children[2].active = true;
break;
case "/dataLibrary/congressMan":
siderList.value[6].active = true;
siderList.value[6].isExpanded = true;
siderList.value[6].children[0].active = true;
break;
case "/dataLibrary/technologyLeader":
case "/dataLibrary/dataTechnologyFigures":
siderList.value[6].active = true;
siderList.value[6].isExpanded = true;
siderList.value[6].children[1].active = true;
break;
case "/dataLibrary/minister":
siderList.value[6].active = true;
siderList.value[6].isExpanded = true;
siderList.value[6].children[2].active = true;
break;
case "/dataLibrary/thinkTankResearcher":
siderList.value[6].active = true;
siderList.value[6].isExpanded = true;
siderList.value[6].children[3].active = true;
break;
case "/dataLibrary/technologyCompany":
case "/dataLibrary/dataCompany":
siderList.value[7].active = true;
siderList.value[7].isExpanded = true;
siderList.value[7].children[0].active = true;
......@@ -580,6 +530,17 @@ onMounted(() => {
siderList.value[7].isExpanded = true;
siderList.value[7].children[2].active = true;
break;
case "/dataLibrary/dataInstitution":
siderList.value[7].active = true;
siderList.value[7].isExpanded = true;
siderList.value[7].children[3].active = true;
break;
case "/dataLibrary/dataNews":
siderList.value[8].active = true;
break;
case "/dataLibrary/keyLab":
siderList.value[9].active = true;
break;
}
});
......
<template>
<div class="countrybill-wrapper">
<div class="header-box">
<div class="header-top">
<SelectBox :placeholder-name="DatePlaceHolder" select-title="成立时间" :select-list="dateList"
:select-name="selectedDate" :custom-time="customTime" @update:select-text="handleSelectDate"
@update:custom-time="handleCustomDate" />
<SelectBox :placeholder-name="countryPlaceHolder" select-title="国家地区"
:select-list="countryList" :select-name="selectedCountry" @update:select-text="handleSelectCountry" />
</div>
<div class="header-footer">
<div class="header-footer-left">
<ActiveTag v-for="tag, index in activeTagList" :key="index" :tagName="tag.name"
@close="handleCloseCurTag(tag, index)" />
</div>
<div class="header-footer-right">
<HeaderBtnBox :isShowAll="isFolderAll" :isShowAllBtn="false" @show-all="handleSwitchFolderAll" @clear="handleClear"
@confirm="handleConfirm" />
</div>
</div>
</div>
<div class="chart-main-box" v-if="isShowChart">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box">
<div class="content-header">
<ChartHeader :list="staticsDemensionList" @clickItem="handleClickDemensionItem">
<template #chart-header-right>
<el-select v-model="selectedTime" placeholder="选择时间" style="width: 150px" v-show="curDemension === '成立时间'"
@change="handleChangeTime">
<el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</ChartHeader>
</div>
<div class="content-main">
<ChartContainer :chartTitle="curChartTitle" :chartTypeList="curChartTypeList"
@clickChartItem="handleSwitchActiveChart" @download="handleDownloadCurChartData">
<template #chart-box>
<LineChart v-if="activeChart === '折线图'" :lineChartData="curChartData" />
<BarChart v-if="activeChart === '柱状图'" :barChartData="curChartData" />
<PieChart v-if="activeChart === '饼状图'" :pieChartData="curChartData" />
<RaderChart v-if="activeChart === '雷达图'" :radarChartData="curChartData" />
</template>
</ChartContainer>
</div>
</div>
</div>
<div class="data-main-box" v-else>
<div class="data-main-box-header">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="data-main-box-main">
<div class="data-main-box-main-header">
<div class="header-left">
<div class="header-left-item1">
<el-checkbox v-model="isSelectedAll" label="全选" @change="handleSelectAllChange" size="large" />
</div>
<div class="header-left-item2 text-tip-1">{{ `已选择${selectedCount}项` }}</div>
<div class="header-left-item2 text-tip-1 cancel" @click="handleClearAll" v-show="selectedCount">{{ '取消' }}
<div class="header-left-item3 text-tip-1" v-if="isShowAllDataMaxLengthTip">{{ `(当前最大选择不能超过1万条!)` }}</div>
</div>
</div>
<div class="header-right">
<div class="header-right-item item1" @click="handleExport">
<div class="icon">
<img src="../assets/icons/download.svg" alt="">
</div>
<div class="text text-tip-1">{{ '导出' }}</div>
</div>
<div class="header-right-item2 item2">
<el-select v-model="curOperation" placeholder="批量操作" style="width: 120px">
<el-option v-for="item in operationList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div class="header-right-item3 item3">
<el-select v-model="isSort" placeholder="成立时间" style="width: 166px" @change="handlePxChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img src="../assets/icons/desc-icon.svg" style="width: 14px; height: 14px" />
</div>
</template>
<el-option v-for="item in releaseTimeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
</div>
<div class="data-main-box-main-content" v-loading="loading" element-loading-text="数据加载中,请稍候...">
<el-table ref="tableRef" :data="tableData" row-key="id" @selection-change="handleSelectionChange"
@select="handleSelect" @select-all="handleSelectAll" style="width: 100%" :row-style="{ height: '52px' }">
<el-table-column type="selection" width="40" />
<el-table-column label="实体名称" width="620">
<template #default="scope">
<span class="title-item text-compact-bold" @click="handleClickToDetail(scope.row)">{{
scope.row.originalTitle
}}</span>
</template>
</el-table-column>
<el-table-column label="成立时间" class-name="date-column">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column label="涉及领域" width="500" class-name="date-column">
<template #default="scope">
<div class="tag-box">
<AreaTag v-for="tag, index in scope.row.domains" :key="index" :tagName="tag" />
</div>
</template>
</el-table-column>
<el-table-column label="实体类型" width="100">
<template #default="scope">{{ scope.row.typeStr }}</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="data-main-box-footer">
<el-pagination background layout="prev, pager, next" :total="totalNum" v-model:current-page="currentPage"
:page-size="pageSize" @current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import ChartContainer from '../components/ChartContainer/index.vue'
import ChartHeader from '../components/ChartHeader/index.vue'
import ActiveTag from '../components/ActiveTag/index.vue'
import HeaderBtnBox from '../components/HeaderBtnBox/index.vue'
import LineChart from '../components/LineChart/index.vue'
import PieChart from '../components/PieChart/index.vue'
import BarChart from '../components/BarChart/index.vue'
import RaderChart from '../components/RadarChart/idnex.vue'
import SelectBox from '../components/SelectBox/index.vue'
import { useRoute } from "vue-router";
import router from '@/router'
import { search } from '@/api/comprehensiveSearch'
import { ElMessage } from 'element-plus'
import getDateRange from '@/utils/getDateRange'
import { getProvinceList, getCountryList, getEntityTypes } from '@/api/comprehensiveSearch/index'
const route = useRoute();
const isShowProvinceBox = computed(() => {
let isShow = false
if (isFolderAll.value && (selectedCountry.value === '0101' || selectedCountry.value === '全部国家')) {
isShow = true
}
return isShow
})
// 图表/数据
const isShowChart = ref(false)
// 点击切换数据/图表
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
if (isShowChart.value) {
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
// setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
if (curDemension.value === '成立时间') {
if (selectedTime.value === '按月度统计') {
curChartData.value = curDemensionItem.data
} else if (selectedTime.value === '按季度统计') {
curChartData.value = curDemensionItem.quatarData
} else {
curChartData.value = curDemensionItem.yearData
}
} else {
curChartData.value = curDemensionItem.data
}
// })
}
}
// 总计数据
const totalNum = ref(0)
// 统计维度列表
const staticsDemensionList = ref([
{
name: '成立时间',
active: true,
chartTypeList: ['折线图', '柱状图'],
chartTitle: '实体清单成立时间变化趋势',
data: {
dataX: [],
dataY: []
},
quatarData: {
dataX: [],
dataY: []
},
yearData: {
dataX: [],
dataY: []
}
},
// {
// name: '科技领域',
// active: false,
// chartTypeList: ['饼状图'],
// chartTitle: '实体清单科技领域分布',
// data: []
// },
// {
// name: '实体类型',
// active: false,
// chartTypeList: ['饼状图'],
// chartTitle: '实体类型分布',
// data: []
// },
{
name: '所属国家地区',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '所属国家地区分布',
data: []
},
// {
// name: '实体省份',
// active: false,
// chartTypeList: ['饼状图'],
// chartTitle: '实体省份分布',
// data: []
// }
])
// 当前维度下的图表列表
const curChartTypeList = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTypeList
})
// 当前图表标题
const curChartTitle = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTitle
})
// 当前维度
const curDemension = ref('成立时间')
// 点击维度item
const handleClickDemensionItem = (val) => {
activeChart.value = ''
staticsDemensionList.value.forEach(item => {
item.active = false
})
val.active = true
curDemension.value = val.name
setTimeout(() => {
activeChart.value = val.chartTypeList[0]
if (curDemension.value === '成立时间' && selectedTime.value === '按年度统计') {
curChartData.value = val.yearData
} else if (curDemension.value === '成立时间' && selectedTime.value === '按季度统计') {
curChartData.value = val.quatarData
} else {
curChartData.value = val.data
}
})
}
// 时间图表 当前选择时间
const selectedTime = ref('按年度统计')
// 时间图表-时间列表
const timeList = ref([
{
label: '按年度统计',
value: '按年度统计'
},
{
label: '按季度统计',
value: '按季度统计'
},
{
label: '按月度统计',
value: '按月度统计'
},
])
const handleChangeTime = value => {
let curChart = activeChart.value
activeChart.value = ''
if (value === '按月度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].data
})
} else if (value === '按季度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].quatarData
})
} else {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].yearData
})
}
}
// 激活的标签列表
const activeTagList = computed(() => {
const arr = []
if (selectedDate.value === '自定义') {
arr.push(
{
tag: '成立时间',
name: customTime.value.join('至')
}
)
}
if (selectedCountry.value && selectedCountry.value !== '全部国家') {
const countryArr = countryList.value.filter(item => item.id === selectedCountry.value)
let countryStr = '全部国家'
if (countryArr && countryArr.length) {
countryStr = countryArr[0].name
}
arr.push(
{
tag: '所属国家地区',
name: countryStr
}
)
}
return arr
})
// 关闭当前标签
const handleCloseCurTag = (tag, index) => {
switch (tag.tag) {
case '成立时间':
selectedDate.value = ''
customTime.value = []
break
case '所属国家地区':
selectedCountry.value = '全部国家'
break
}
}
const activeChart = ref('') // 当前激活的图表
// 切换当前图表
const handleSwitchActiveChart = val => {
activeChart.value = val.name
}
// 数据- 是否全选
const isSelectedAll = ref(false)
// 批量操作-当前操作
const curOperation = ref('')
const operationList = ref([
{
name: 'aaa',
id: 'aaa'
},
{
name: 'bbb',
id: 'bbb'
},
{
name: 'ccc',
id: 'ccc'
},
])
// 成立时间
const DatePlaceHolder = ref('请选择时间')
const selectedDate = ref('')
const dateList = ref([
{
name: '自定义',
id: '自定义'
},
{
name: '近一年',
id: '近一年'
},
{
name: '近半年',
id: '近半年'
},
{
name: '近三月',
id: '近三月'
},
{
name: '近一月',
id: '近一月'
}
])
const customTime = ref([]) // 自定义时间
const handleCustomDate = value => {
customTime.value = value
}
const handleSelectDate = (value) => {
selectedDate.value = value
if (selectedDate.value !== '自定义') {
customTime.value = getDateRange(selectedDate.value)
}
}
// 所属国家地区
const countryList = ref([
{
name: '全部国家',
id: '全部国家'
},
])
const selectedCountry = ref('全部国家')
const countryPlaceHolder = ref('请选择实体国家')
const handleSelectCountry = value => {
selectedCountry.value = value
}
// 获取国家地区列表
const handleGetCountryList = async () => {
try {
const res = await getCountryList()
console.log('获取国家列表', res);
if (res.code === 200 && res.data) {
countryList.value = res.data.map(item => {
return {
name: item.name,
id: item.id
}
})
}
} catch (error) {
}
}
// 清空条件
const handleClear = () => {
selectedDate.value = ''
customTime.value = []
selectedCountry.value = '全部国家'
ElMessage.success('已清空条件!')
}
// 确定
const handleConfirm = () => {
currentPage.value = 1
fetchTableData()
}
// 展开全部 / 收起
const isFolderAll = ref(false)
const handleSwitchFolderAll = () => {
isFolderAll.value = !isFolderAll.value
}
const tableRef = ref(null)
// 表格数据
const tableData = ref([
])
const releaseTimeList = ref([
{
label: "按发布时间倒序",
value: true
},
{
label: "按发布时间升序",
value: false
}
]);
const isSort = ref(true); // true 倒序 false 升序
const handlePxChange = val => {
fetchTableData()
};
const currentPage = ref(1);
const pageSize = ref(10)
// 存储选中的数据(跨页)[citation:3][citation:8]
const selectedMap = ref(new Map()) // 使用 Map 存储,key 为唯一 id
// 计算已选中的条数
const selectedCount = computed(() => selectedMap.value.size)
// 获取当前页表格数据(示例)
const fetchTableData = async () => {
// isSelectedAll.value = false
// selectedMap.value.clear()
loading.value = true
// 调用接口获取数据...
const params = {
page: currentPage.value,
size: pageSize.value,
// keyword: '',
type: 7, // 政府机构
proposedDateStart: customTime.value[0] ? customTime.value[0] : null,
proposedDateEnd: customTime.value[1] ? customTime.value[1] : null,
countryId: selectedCountry.value === '全部国家' ? null : selectedCountry.value, // 国家地区
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
tableData.value = res.data.records
totalNum.value = res.data.total
staticsDemensionList.value[0].data = {
dataX: Object.keys(res.data.aggregationsDate),
dataY: Object.values(res.data.aggregationsDate).map(value => Number(value))
}
staticsDemensionList.value[0].quatarData = {
dataX: Object.keys(res.data.aggregationsQuarter),
dataY: Object.values(res.data.aggregationsQuarter).map(value => Number(value))
}
staticsDemensionList.value[0].yearData = {
dataX: Object.keys(res.data.aggregationsYear),
dataY: Object.values(res.data.aggregationsYear).map(value => Number(value))
}
staticsDemensionList.value[1].data = Object.entries(res.data.aggregationCountryId).map(([key, value]) => ({
name: key,
value: Number(value)
}))
// staticsDemensionList.value[2].data = Object.entries(res.data.aggregationSentityTypeCode).map(([key, value]) => ({
// name: key,
// value: Number(value)
// }))
// staticsDemensionList.value[3].data = Object.entries(res.data.aggregationCountryId).map(([key, value]) => ({
// name: key,
// value: Number(value)
// }))
// staticsDemensionList.value[4].data = Object.entries(res.data.aggregationProvinceName).map(([key, value]) => ({
// name: key,
// value: Number(value)
// }))
}
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
activeChart.value = ''
setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
curChartData.value = curDemensionItem.data
})
loading.value = false
} catch (error) {
loading.value = false
}
// tableData.value = res.data
// total.value = res.total
// 数据加载后,回显已选中的行
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
}
const allData = ref([])
// 获取筛选条件下全部表格数据
const fetchAllData = async () => {
const params = {
page: 1,
size: 9999,
type: 7, // 政府机构
proposedDateStart: customTime.value[0] ? customTime.value[0] : null,
proposedDateEnd: customTime.value[1] ? customTime.value[1] : null,
countryId: selectedCountry.value === '全部国家' ? null : selectedCountry.value, // 国家地区
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
allData.value = res.data.records
}
} catch (error) {
ElMessage.error('加载全部数据出错!')
}
}
// 单选事件
const handleSelect = (selection, row) => {
if (selection.some(item => item.id === row.id)) {
// 选中:添加到 Map
selectedMap.value.set(row.id, row)
} else {
// 取消选中:从 Map 移除
selectedMap.value.delete(row.id)
}
}
// 表格自带 当前页 全选/全不选事件
const handleSelectAll = (selection) => {
if (selection.length > 0) {
// 全选:将当前页所有数据添加到 Map
tableData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
} else {
// 全不选:从 Map 中移除当前页的所有数据
tableData.value.forEach(row => {
selectedMap.value.delete(row.id)
})
}
}
// 处理选择变化(用于统计)
const handleSelectionChange = (val) => {
// 这里可以做一些额外的处理,但主要统计使用 selectedMap
console.log('当前页选中数量:', val.length)
}
// 全选当前页按钮
const handleSelectAllPage = () => {
if (tableData.value.length === 0) return
// 检查当前页是否已全选
const currentPageSelected = tableData.value.every(row =>
selectedMap.value.has(row.id)
)
if (currentPageSelected) {
// 已全选,则不动当前页的全选
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, false)
// selectedMap.value.delete(row.id)
})
} else {
// 未全选,则全选当前页
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, true)
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
}
}
// 全选最大1万条提示
const isShowAllDataMaxLengthTip = ref(false)
const loading = ref(false) // 加载数据loading
// 处理 全选(全部数据)
const handleSelectAllChange = async () => {
if (isSelectedAll.value) {
if (totalNum.value > 10000) {
isShowAllDataMaxLengthTip.value = true
}
loading.value = true
await fetchAllData()
handleSelectAllPage()
allData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
loading.value = false
} else {
handleClearAll()
}
}
// 清空所有选择
const handleClearAll = () => {
isSelectedAll.value = false
selectedMap.value.clear()
tableRef.value?.clearSelection()
}
// 翻页
const handleCurrentChange = async (val) => {
currentPage.value = val
await fetchTableData()
if (isSelectedAll.value) {
handleSelectAllPage()
}
}
// 监听数据变化,回显选中状态 [citation:4][citation:8]
watch(tableData, () => {
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
})
// 当前图表数据
const curChartData = ref(null)
// 下载当前图表数据
const handleDownloadCurChartData = () => {
const jsonStr = JSON.stringify(curChartData.value, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'chartData.json';
link.click();
URL.revokeObjectURL(url);
}
// 跳转到当前页 初始化筛选条件
const initParam = () => {
const hasQuery = Object.keys(route.query).length > 0;
if (hasQuery) {
if (route.query.selectedDate && Array.isArray(JSON.parse(route.query.selectedDate)) && JSON.parse(route.query.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(route.query.selectedDate)
}
selectedCountry.value = route.query.selectedCountryId ? route.query.selectedCountryId : '全部国家'
const query = route.query;
if (Object.keys(query).length > 0) {
sessionStorage.setItem('entityRouteQuery', JSON.stringify(query));
}
} else {
const savedQuery = JSON.parse(sessionStorage.getItem('entityRouteQuery') || '{}');
if (savedQuery.selectedDate && Array.isArray(JSON.parse(savedQuery.selectedDate)) && JSON.parse(savedQuery.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(savedQuery.selectedDate)
}
selectedCountry.value = route.query.selectedCountryId ? route.query.selectedCountryId : '全部国家'
}
}
// 跳转机构详情
const handleClickToDetail = (item) => {
console.log('item', item);
window.sessionStorage.setItem("curTabName", item.originalTitle);
const route = router.resolve({
path: "/institution",
query: {
id: item.id
}
});
window.open(route.href, "_blank");
};
// 导出
const handleExport = () => {
if (!selectedCount.value) {
ElMessage.warning('请选择至少一项数据!')
return
}
console.log(selectedMap.value);
const arr = Array.from(selectedMap.value);
const jsonStr = JSON.stringify(arr, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'export.json';
link.click();
URL.revokeObjectURL(url);
};
onMounted(async () => {
await handleGetCountryList() // 获取国家列表
initParam()
// 初始化
await fetchTableData()
})
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
overflow: hidden;
overflow-y: auto;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
min-height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
box-sizing: border-box;
padding: 16px 24px;
.header-top {
min-height: 28px;
display: flex;
flex-wrap: wrap;
gap: 12px 42px;
// transition: all ease 1s;
.check-box {
display: flex;
width: 348px;
height: 28px;
align-items: center;
gap: 8px;
.check-box-left {
width: 100px;
color: var(--text-primary-65-color);
}
}
}
.header-footer {
margin-top: 16px;
display: flex;
justify-content: space-between;
.header-footer-left {
display: flex;
justify-content: space-between;
gap: 8px;
}
}
}
.chart-main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
.content-header {
margin: 16px 24px;
width: 1520px;
height: 28px;
}
.content-main {
width: 1520px;
margin: 0 auto;
}
}
}
.data-main-box {
width: 1568px;
min-height: 810px;
border-radius: 10px;
background: var(--bg-white-100);
margin: 0 auto;
margin-bottom: 20px;
overflow: hidden;
.data-main-box-header {
margin: 16px auto;
width: 1520px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
box-sizing: border-box;
padding: 2px 0;
color: var(--color-red-100);
}
}
.data-main-box-main {
width: 1520px;
// height: 633px;
min-height: 680px;
border-radius: 10px;
border: 1px solid var(--bg-black-5);
margin: 0 auto;
.data-main-box-main-header {
height: 48px;
background: var(--bg-black-2);
display: flex;
justify-content: space-between;
.header-left {
margin-left: 16px;
height: 48px;
display: flex;
gap: 16px;
align-items: center;
.header-left-item2 {
color: var(--color-primary-100);
display: flex;
gap: 8px;
}
.header-left-item3 {
color: var(--color-orange-100);
}
.cancel {
cursor: pointer;
}
}
.header-right {
margin-right: 16px;
display: flex;
gap: 8px;
align-items: center;
.header-right-item {
height: 30px;
padding: 5px 16px;
border: 1px solid var(--bg-black-10);
border-radius: 4px;
background: var(--bg-white-100);
cursor: pointer;
}
.item1 {
display: flex;
gap: 2px;
justify-content: center;
align-items: center;
&:hover {
background: var(--color-primary-2);
}
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
color: var(--text-primary-65-color);
}
}
.item2 {}
.item3 {}
}
}
.data-main-box-main-content {}
}
.data-main-box-footer {
margin: 16px auto 0;
height: 40px;
width: 1520px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
.date-column {
background-color: #ecf5ff;
.tag-box {
display: flex;
flex-wrap: wrap;
gap: 8px;
width: 490px;
}
}
.date-column .cell {
color: #409eff !important;
font-weight: 500;
}
.title-item {
color: var(--text-primary-80-color);
cursor: pointer;
&:hover {
color: var(--color-primary-100);
text-decoration: underline;
}
}
.person-item {
color: var(--color-primary-100);
cursor: pointer;
&:hover {
font-weight: bold;
text-decoration: underline;
}
}
:deep(.el-table__header-wrapper) {
// background-color: #f5f7fa;
height: 48px;
}
:deep(.el-table__header th) {
// background-color: #f5f7fa;
color: var(--text-primary-50-color);
font-weight: bold;
}
</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">
<div class="header-top">
<SelectBox :placeholder-name="areaPlaceHolder" select-title="科技领域" :select-list="areaList"
:select-name="selectedArea" @update:select-text="handleSelectArea" />
<SelectBox :placeholder-name="DatePlaceHolder" select-title="发布时间" :select-list="dateList"
:select-name="selectedDate" :custom-time="customTime" @update:select-text="handleSelectDate"
@update:custom-time="handleCustomDate" />
<SelectBox :placeholder-name="sourceMediaPlaceHolder" select-title="来源媒体" :select-list="sourceMediaList"
:select-name="selectedSourceMedia" @update:select-text="handleSelectSourceMedia" />
</div>
<div class="header-footer">
<div class="header-footer-left">
<ActiveTag v-for="tag, index in activeTagList" :key="index" :tagName="tag.name"
@close="handleCloseCurTag(tag, index)" />
</div>
<div class="header-footer-right">
<HeaderBtnBox :isShowAll="isFolderAll" :isShowAllBtn="false" @show-all="handleSwitchFolderAll"
@clear="handleClear" @confirm="handleConfirm" />
</div>
</div>
</div>
<div class="chart-main-box" v-if="isShowChart">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box">
<div class="content-header">
<ChartHeader :list="staticsDemensionList" @clickItem="handleClickDemensionItem">
<template #chart-header-right>
<el-select v-model="selectedTime" placeholder="选择时间" style="width: 150px" v-show="curDemension === '发布时间'"
@change="handleChangeTime">
<el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</ChartHeader>
</div>
<div class="content-main">
<ChartContainer :chartTitle="curChartTitle" :chartTypeList="curChartTypeList"
@clickChartItem="handleSwitchActiveChart" @download="handleDownloadCurChartData">
<template #chart-box>
<LineChart v-if="activeChart === '折线图'" :lineChartData="curChartData" />
<BarChart v-if="activeChart === '柱状图'" :barChartData="curChartData" />
<PieChart v-if="activeChart === '饼状图'" :pieChartData="curChartData" />
<RaderChart v-if="activeChart === '雷达图'" :radarChartData="curChartData" />
</template>
</ChartContainer>
</div>
</div>
</div>
<div class="data-main-box" v-else>
<div class="data-main-box-header">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="data-main-box-main">
<div class="data-main-box-main-header">
<div class="header-left">
<div class="header-left-item1">
<el-checkbox v-model="isSelectedAll" label="全选" @change="handleSelectAllChange" size="large" />
</div>
<div class="header-left-item2 text-tip-1">{{ `已选择${selectedCount}项` }}</div>
<div class="header-left-item2 text-tip-1 cancel" @click="handleClearAll" v-show="selectedCount">{{ '取消' }}
<div class="header-left-item3 text-tip-1" v-if="isShowAllDataMaxLengthTip">{{ `(当前最大选择不能超过1万条!)` }}</div>
</div>
</div>
<div class="header-right">
<div class="header-right-item item1" @click="handleExport">
<div class="icon">
<img src="../assets/icons/download.svg" alt="">
</div>
<div class="text text-tip-1">{{ '导出' }}</div>
</div>
<div class="header-right-item2 item2">
<el-select v-model="curOperation" placeholder="批量操作" style="width: 120px">
<el-option v-for="item in operationList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div class="header-right-item3 item3">
<el-select v-model="isSort" placeholder="发布时间" style="width: 166px" @change="handlePxChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img src="../assets/icons/desc-icon.svg" style="width: 14px; height: 14px" />
</div>
</template>
<el-option v-for="item in releaseTimeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
</div>
<div class="data-main-box-main-content" v-loading="loading" element-loading-text="数据加载中,请稍候...">
<el-table ref="tableRef" :data="tableData" row-key="id" @selection-change="handleSelectionChange"
@select="handleSelect" @select-all="handleSelectAll" style="width: 100%" :row-style="{ height: '52px' }">
<el-table-column type="selection" width="40" />
<el-table-column label="新闻标题" width="720">
<template #default="scope">
<span class="title-item text-compact-bold" @click="handleClickToDetail(scope.row)">{{
scope.row.originalTitle
}}</span>
</template>
</el-table-column>
<el-table-column label="发布时间" width="120" class-name="date-column">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column label="来源媒体">
<template #default="scope">
<span class="person-item text-compact">{{ scope.row.organizationName
}}</span>
</template>
</el-table-column>
<el-table-column label="涉及领域" width="350" class-name="date-column">
<template #default="scope">
<div class="tag-box">
<AreaTag v-for="tag, index in scope.row.domains" :key="index" :tagName="tag" />
</div>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="data-main-box-footer">
<el-pagination background layout="prev, pager, next" :total="totalNum" v-model:current-page="currentPage"
:page-size="pageSize" @current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import ChartContainer from '../components/ChartContainer/index.vue'
import ChartHeader from '../components/ChartHeader/index.vue'
import ActiveTag from '../components/ActiveTag/index.vue'
import HeaderBtnBox from '../components/HeaderBtnBox/index.vue'
import LineChart from '../components/LineChart/index.vue'
import PieChart from '../components/PieChart/index.vue'
import BarChart from '../components/BarChart/index.vue'
import RaderChart from '../components/RadarChart/idnex.vue'
import SelectBox from '../components/SelectBox/index.vue'
import { useRoute } from "vue-router";
import router from '@/router'
import { search } from '@/api/comprehensiveSearch'
import { ElMessage } from 'element-plus'
import getDateRange from '@/utils/getDateRange'
import { useGotoNewsDetail } from "@/router/modules/news";
const gotoNewsDetail = useGotoNewsDetail();
const route = useRoute();
// 图表/数据
const isShowChart = ref(false)
// 点击切换数据/图表
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
if (isShowChart.value) {
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
// setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
if (curDemension.value === '发布时间') {
if (selectedTime.value === '按月度统计') {
curChartData.value = curDemensionItem.data
} else if (selectedTime.value === '按季度统计') {
curChartData.value = curDemensionItem.quatarData
} else {
curChartData.value = curDemensionItem.yearData
}
} else {
curChartData.value = curDemensionItem.data
}
// })
}
}
// 总计数据
const totalNum = ref(0)
// 统计维度列表
const staticsDemensionList = ref([
{
name: '发布时间',
active: true,
chartTypeList: ['折线图', '柱状图'],
chartTitle: '新闻发布数量随时间变化趋势',
data: {
dataX: [],
dataY: []
},
quatarData: {
dataX: [],
dataY: []
},
yearData: {
dataX: [],
dataY: []
}
},
{
name: '科技领域',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '新闻领域分布',
data: []
},
{
name: '来源媒体',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '新闻来源媒体分布',
data: []
}
])
// 当前维度下的图表列表
const curChartTypeList = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTypeList
})
// 当前图表标题
const curChartTitle = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTitle
})
// 当前维度
const curDemension = ref('发布时间')
// 点击维度item
const handleClickDemensionItem = (val) => {
activeChart.value = ''
staticsDemensionList.value.forEach(item => {
item.active = false
})
val.active = true
curDemension.value = val.name
setTimeout(() => {
activeChart.value = val.chartTypeList[0]
if (curDemension.value === '发布时间' && selectedTime.value === '按年度统计') {
curChartData.value = val.yearData
} else if (curDemension.value === '发布时间' && selectedTime.value === '按季度统计') {
curChartData.value = val.quatarData
} else {
curChartData.value = val.data
}
})
}
// 时间图表 当前选择时间
const selectedTime = ref('按年度统计')
// 时间图表-时间列表
const timeList = ref([
{
label: '按年度统计',
value: '按年度统计'
},
{
label: '按季度统计',
value: '按季度统计'
},
{
label: '按月度统计',
value: '按月度统计'
},
])
const handleChangeTime = value => {
let curChart = activeChart.value
activeChart.value = ''
if (value === '按月度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].data
})
} else if (value === '按季度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].quatarData
})
} else {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].yearData
})
}
}
// 激活的标签列表
const activeTagList = computed(() => {
const arr = []
if (selectedArea.value && selectedArea.value !== '全部领域') {
arr.push(
{
tag: '科技领域',
name: selectedArea.value
}
)
}
if (selectedDate.value === '自定义') {
arr.push(
{
tag: '发布时间',
name: customTime.value.join('至')
}
)
}
if (selectedSourceMedia.value && selectedSourceMedia.value !== '全部来源媒体') {
arr.push(
{
tag: '来源媒体',
name: selectedSourceMedia.value
}
)
}
return arr
})
// 关闭当前标签
const handleCloseCurTag = (tag, index) => {
switch (tag.tag) {
case '科技领域':
selectedArea.value = '全部领域'
break
case '发布时间':
selectedDate.value = ''
customTime.value = []
break
case '来源媒体':
selectedSourceMedia.value = '全部来源媒体'
break
}
}
const activeChart = ref('') // 当前激活的图表
// 切换当前图表
const handleSwitchActiveChart = val => {
activeChart.value = val.name
}
// 数据- 是否全选
const isSelectedAll = ref(false)
// 批量操作-当前操作
const curOperation = ref('')
const operationList = ref([
])
// 科技领域
const areaPlaceHolder = ref('请选择领域')
const selectedArea = ref('全部领域')
const areaList = ref([
{
name: '全部领域',
id: '全部领域'
},
{
name: '人工智能',
id: '人工智能'
},
{
name: '生物科技',
id: '生物科技'
},
{
name: '新一代通信网络',
id: '新一代通信网络'
},
{
name: '量子科技',
id: '量子科技'
},
{
name: '新能源',
id: '新能源'
},
{
name: '集成电路',
id: '集成电路'
},
{
name: '海洋',
id: '海洋'
},
{
name: '先进制造',
id: '先进制造'
},
{
name: '新材料',
id: '新材料'
},
{
name: '航空航天',
id: '航空航天'
},
{
name: '太空',
id: '太空'
},
{
name: '深海',
id: '深海'
},
{
name: '极地',
id: '极地'
},
{
name: '核',
id: '核'
},
{
name: '其他',
id: '其他'
},
])
const handleSelectArea = (value) => {
selectedArea.value = value
}
// 提出时间
const DatePlaceHolder = ref('请选择时间')
const selectedDate = ref('')
const dateList = ref([
{
name: '自定义',
id: '自定义'
},
{
name: '近一年',
id: '近一年'
},
{
name: '近半年',
id: '近半年'
},
{
name: '近三月',
id: '近三月'
},
{
name: '近一月',
id: '近一月'
}
])
const customTime = ref([]) // 自定义时间
const handleCustomDate = value => {
customTime.value = value
}
const handleSelectDate = (value) => {
selectedDate.value = value
if (selectedDate.value !== '自定义') {
customTime.value = getDateRange(selectedDate.value)
}
}
// 来源媒体
const sourceMediaList = ref([
{
name: '全部来源媒体',
id: '全部来源媒体'
},
])
const selectedSourceMedia = ref('全部来源媒体')
const sourceMediaPlaceHolder = ref('请选择来源媒体')
const handleSelectSourceMedia = value => {
selectedSourceMedia.value = value
}
// 清空条件
const handleClear = () => {
selectedArea.value = '全部领域'
selectedDate.value = ''
customTime.value = []
selectedSourceMedia.value = '全部来源媒体'
ElMessage.success('已清空条件!')
}
// 确定
const handleConfirm = () => {
currentPage.value = 1
fetchTableData()
}
// 展开全部 / 收起
const isFolderAll = ref(false)
const handleSwitchFolderAll = () => {
isFolderAll.value = !isFolderAll.value
}
const tableRef = ref(null)
// 表格数据
const tableData = ref([
])
const releaseTimeList = ref([
{
label: "按发布时间倒序",
value: true
},
{
label: "按发布时间升序",
value: false
}
]);
const isSort = ref(true); // true 倒序 false 升序
const handlePxChange = val => {
fetchTableData()
};
const currentPage = ref(1);
const pageSize = ref(10)
// 存储选中的数据(跨页)[citation:3][citation:8]
const selectedMap = ref(new Map()) // 使用 Map 存储,key 为唯一 id
// 计算已选中的条数
const selectedCount = computed(() => selectedMap.value.size)
// 获取当前页表格数据(示例)
const fetchTableData = async () => {
// isSelectedAll.value = false
// selectedMap.value.clear()
loading.value = true
// 调用接口获取数据...
const params = {
page: currentPage.value,
size: pageSize.value,
// keyword: '',
type: 8, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
domains: selectedArea.value === '全部领域' ? null : [selectedArea.value],
proposedDateStart: customTime.value[0] ? customTime.value[0] : null,
proposedDateEnd: customTime.value[1] ? customTime.value[1] : null,
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
tableData.value = res.data.records
totalNum.value = res.data.total
staticsDemensionList.value[0].data = {
dataX: Object.keys(res.data.aggregationsDate),
dataY: Object.values(res.data.aggregationsDate).map(value => Number(value))
}
staticsDemensionList.value[0].quatarData = {
dataX: Object.keys(res.data.aggregationsQuarter),
dataY: Object.values(res.data.aggregationsQuarter).map(value => Number(value))
}
staticsDemensionList.value[0].yearData = {
dataX: Object.keys(res.data.aggregationsYear),
dataY: Object.values(res.data.aggregationsYear).map(value => Number(value))
}
staticsDemensionList.value[1].data = Object.entries(res.data.aggregationsDomain).map(([key, value]) => ({
name: key,
value: Number(value)
}))
staticsDemensionList.value[2].data = Object.entries(res.data.aggregationsorganizationName).map(([key, value]) => ({
name: key,
value: Number(value)
}))
}
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
activeChart.value = ''
setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
curChartData.value = curDemensionItem.data
})
} catch (error) {
console.error(error);
} finally {
loading.value = false
}
// 数据加载后,回显已选中的行
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
}
const allData = ref([])
// 获取筛选条件下全部表格数据
const fetchAllData = async () => {
const params = {
page: 1,
size: 9999,
// keyword: '',
type: 8, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
domains: selectedArea.value === '全部领域' ? null : [selectedArea.value],
proposedDateStart: customTime.value[0],
proposedDateEnd: customTime.value[1],
sort: isSort.value ? 0 : 1
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
allData.value = res.data.records
}
} catch (error) {
ElMessage.error('加载全部数据出错!')
}
}
// 单选事件
const handleSelect = (selection, row) => {
if (selection.some(item => item.id === row.id)) {
// 选中:添加到 Map
selectedMap.value.set(row.id, row)
} else {
// 取消选中:从 Map 移除
selectedMap.value.delete(row.id)
}
}
// 表格自带 当前页 全选/全不选事件
const handleSelectAll = (selection) => {
if (selection.length > 0) {
// 全选:将当前页所有数据添加到 Map
tableData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
} else {
// 全不选:从 Map 中移除当前页的所有数据
tableData.value.forEach(row => {
selectedMap.value.delete(row.id)
})
}
}
// 处理选择变化(用于统计)
const handleSelectionChange = (val) => {
// 这里可以做一些额外的处理,但主要统计使用 selectedMap
console.log('当前页选中数量:', val.length)
}
// 全选当前页按钮
const handleSelectAllPage = () => {
if (tableData.value.length === 0) return
// 检查当前页是否已全选
const currentPageSelected = tableData.value.every(row =>
selectedMap.value.has(row.id)
)
if (currentPageSelected) {
// 已全选,则不动当前页的全选
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, false)
// selectedMap.value.delete(row.id)
})
} else {
// 未全选,则全选当前页
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, true)
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
}
}
// 全选最大1万条提示
const isShowAllDataMaxLengthTip = ref(false)
const loading = ref(false) // 加载数据loading
// 处理 全选(全部数据)
const handleSelectAllChange = async () => {
if (isSelectedAll.value) {
if (totalNum.value > 10000) {
isShowAllDataMaxLengthTip.value = true
}
loading.value = true
await fetchAllData()
handleSelectAllPage()
allData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
loading.value = false
} else {
handleClearAll()
}
}
// 清空所有选择
const handleClearAll = () => {
isSelectedAll.value = false
selectedMap.value.clear()
tableRef.value?.clearSelection()
}
// 翻页
const handleCurrentChange = async (val) => {
currentPage.value = val
await fetchTableData()
if (isSelectedAll.value) {
handleSelectAllPage()
}
}
// 监听数据变化,回显选中状态 [citation:4][citation:8]
watch(tableData, () => {
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
})
// 当前图表数据
const curChartData = ref(null)
// 下载当前图表数据
const handleDownloadCurChartData = () => {
const jsonStr = JSON.stringify(curChartData.value, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'chartData.json';
link.click();
URL.revokeObjectURL(url);
}
// 跳转到当前页 初始化筛选条件
const initParam = () => {
const hasQuery = Object.keys(route.query).length > 0;
if (hasQuery) {
selectedArea.value = route.query.domains ? route.query.domains : '全部领域'
if (route.query.selectedDate && Array.isArray(JSON.parse(route.query.selectedDate)) && JSON.parse(route.query.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(route.query.selectedDate)
}
selectedSourceMedia.value = route.query.orgnizationName ? route.query.orgnizationName : '全部来源媒体'
const query = route.query;
if (Object.keys(query).length > 0) {
sessionStorage.setItem('decreeRouteQuery', JSON.stringify(query));
}
} else {
const savedQuery = JSON.parse(sessionStorage.getItem('decreeRouteQuery') || '{}');
selectedArea.value = savedQuery.domains ? savedQuery.domains : '全部领域'
if (savedQuery.selectedDate && Array.isArray(JSON.parse(savedQuery.selectedDate)) && JSON.parse(savedQuery.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(savedQuery.selectedDate)
}
}
}
// 跳转新闻详情
const handleClickToDetail = (item) => {
console.log('item', item);
window.sessionStorage.setItem("curTabName", item.originalTitle);
gotoNewsDetail(item.id);
// const route = router.resolve({
// path: "/newsAnalysis",
// query: {
// newsId: item.id
// }
// });
// window.open(route.href, "_blank");
};
// 导出
const handleExport = () => {
if (!selectedCount.value) {
ElMessage.warning('请选择至少一项数据!')
return
}
console.log(selectedMap.value);
const arr = Array.from(selectedMap.value);
const jsonStr = JSON.stringify(arr, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'export.json';
link.click();
URL.revokeObjectURL(url);
};
onMounted(async () => {
initParam()
// 初始化
await fetchTableData()
})
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
overflow: hidden;
overflow-y: auto;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
min-height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
box-sizing: border-box;
padding: 16px 24px;
.header-top {
min-height: 28px;
display: flex;
flex-wrap: wrap;
gap: 12px 42px;
// transition: all ease 1s;
.check-box {
display: flex;
width: 348px;
height: 28px;
align-items: center;
gap: 8px;
.check-box-left {
width: 100px;
color: var(--text-primary-65-color);
}
}
}
.header-footer {
margin-top: 16px;
display: flex;
justify-content: space-between;
.header-footer-left {
display: flex;
justify-content: space-between;
gap: 8px;
}
}
}
.chart-main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
.content-header {
margin: 16px 24px;
width: 1520px;
height: 28px;
}
.content-main {
width: 1520px;
margin: 0 auto;
}
}
}
.data-main-box {
width: 1568px;
min-height: 810px;
border-radius: 10px;
background: var(--bg-white-100);
margin: 0 auto;
margin-bottom: 20px;
overflow: hidden;
.data-main-box-header {
margin: 16px auto;
width: 1520px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
box-sizing: border-box;
padding: 2px 0;
color: var(--color-red-100);
}
}
.data-main-box-main {
width: 1520px;
// height: 633px;
min-height: 680px;
border-radius: 10px;
border: 1px solid var(--bg-black-5);
margin: 0 auto;
.data-main-box-main-header {
height: 48px;
background: var(--bg-black-2);
display: flex;
justify-content: space-between;
.header-left {
margin-left: 16px;
height: 48px;
display: flex;
gap: 16px;
align-items: center;
.header-left-item2 {
color: var(--color-primary-100);
display: flex;
gap: 8px;
}
.header-left-item3 {
color: var(--color-orange-100);
}
.cancel {
cursor: pointer;
}
}
.header-right {
margin-right: 16px;
display: flex;
gap: 8px;
align-items: center;
.header-right-item {
height: 30px;
padding: 5px 16px;
border: 1px solid var(--bg-black-10);
border-radius: 4px;
background: var(--bg-white-100);
cursor: pointer;
}
.item1 {
display: flex;
gap: 2px;
justify-content: center;
align-items: center;
&:hover {
background: var(--color-primary-2);
}
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
color: var(--text-primary-65-color);
}
}
.item2 {}
.item3 {}
}
}
.data-main-box-main-content {}
}
.data-main-box-footer {
margin: 16px auto 0;
height: 40px;
width: 1520px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
.date-column {
background-color: #ecf5ff;
.tag-box {
display: flex;
flex-wrap: wrap;
gap: 8px;
width: 340px;
}
}
.date-column .cell {
color: #409eff !important;
font-weight: 500;
}
.title-item {
color: var(--text-primary-80-color);
cursor: pointer;
&:hover {
color: var(--color-primary-100);
text-decoration: underline;
}
}
.person-item {
color: var(--color-primary-100);
cursor: pointer;
&:hover {
font-weight: bold;
text-decoration: underline;
}
}
:deep(.el-table__header-wrapper) {
// background-color: #f5f7fa;
height: 48px;
}
:deep(.el-table__header th) {
// background-color: #f5f7fa;
color: var(--text-primary-50-color);
font-weight: bold;
}
/* 针对特定列 */
// :deep(.el-table__header th:first-child) {
// background-color: #e6f7ff;
// color: #1890ff;
// }</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">
<div class="header-top">
<SelectBox :placeholder-name="areaPlaceHolder" select-title="科技领域" :select-list="areaList"
:select-name="selectedArea" @update:select-text="handleSelectArea" />
<SelectBox :placeholder-name="DatePlaceHolder" select-title="发布时间" :select-list="dateList"
:select-name="selectedDate" :custom-time="customTime" @update:select-text="handleSelectDate"
@update:custom-time="handleCustomDate" />
<SelectBox v-if="isFolderAll" :placeholder-name="insPlaceHolder" select-title="发布机构" :select-list="insList"
:select-name="selectedIns" @update:select-text="handleSelectIns" />
<SelectBox v-if="isFolderAll" :placeholder-name="decreeTypePlaceHolder" select-title="政令类型"
:select-list="decreeTypeList" :select-name="selectedDecreeType"
@update:select-text="handleSelectDecreeType" />
<div class="check-box">
<div class="check-box-left text-tip-1">
{{ '是否涉华:' }}
</div>
<div class="check-box-right">
<el-checkbox v-model="isInvolveCn" class="involve-checkbox">
{{ '只看涉华政令' }}
</el-checkbox>
</div>
</div>
<div class="check-box">
<div class="check-box-left text-tip-1">
{{ '科技相关:' }}
</div>
<div class="check-box-right">
<el-checkbox v-model="isInvolveTechnology" class="involve-checkbox">
{{ '只看科技相关' }}
</el-checkbox>
</div>
</div>
</div>
<div class="header-footer">
<div class="header-footer-left">
<ActiveTag v-for="tag, index in activeTagList" :key="index" :tagName="tag.name"
@close="handleCloseCurTag(tag, index)" />
</div>
<div class="header-footer-right">
<HeaderBtnBox :isShowAll="isFolderAll" @show-all="handleSwitchFolderAll" @clear="handleClear"
@confirm="handleConfirm" />
</div>
</div>
</div>
<div class="chart-main-box" v-if="isShowChart">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box">
<div class="content-header">
<ChartHeader :list="staticsDemensionList" @clickItem="handleClickDemensionItem">
<template #chart-header-right>
<el-select v-model="selectedTime" placeholder="选择时间" style="width: 150px" v-show="curDemension === '发布时间'"
@change="handleChangeTime">
<el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</ChartHeader>
</div>
<div class="content-main">
<ChartContainer :chartTitle="curChartTitle" :chartTypeList="curChartTypeList"
@clickChartItem="handleSwitchActiveChart" @download="handleDownloadCurChartData">
<template #chart-box>
<LineChart v-if="activeChart === '折线图'" :lineChartData="curChartData" />
<BarChart v-if="activeChart === '柱状图'" :barChartData="curChartData" />
<PieChart v-if="activeChart === '饼状图'" :pieChartData="curChartData" />
<RaderChart v-if="activeChart === '雷达图'" :radarChartData="curChartData" />
</template>
</ChartContainer>
</div>
</div>
</div>
<div class="data-main-box" v-else>
<div class="data-main-box-header">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="data-main-box-main">
<div class="data-main-box-main-header">
<div class="header-left">
<div class="header-left-item1">
<el-checkbox v-model="isSelectedAll" label="全选" @change="handleSelectAllChange" size="large" />
</div>
<div class="header-left-item2 text-tip-1">{{ `已选择${selectedCount}项` }}</div>
<div class="header-left-item2 text-tip-1 cancel" @click="handleClearAll" v-show="selectedCount">{{ '取消' }}
<div class="header-left-item3 text-tip-1" v-if="isShowAllDataMaxLengthTip">{{ `(当前最大选择不能超过1万条!)` }}</div>
</div>
</div>
<div class="header-right">
<div class="header-right-item item1" @click="handleExport">
<div class="icon">
<img src="../assets/icons/download.svg" alt="">
</div>
<div class="text text-tip-1">{{ '导出' }}</div>
</div>
<div class="header-right-item2 item2">
<el-select v-model="curOperation" placeholder="批量操作" style="width: 120px">
<el-option v-for="item in operationList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div class="header-right-item3 item3">
<el-select v-model="isSort" placeholder="发布时间" style="width: 166px" @change="handlePxChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img src="../assets/icons/desc-icon.svg" style="width: 14px; height: 14px" />
</div>
</template>
<el-option v-for="item in releaseTimeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
</div>
<div class="data-main-box-main-content" v-loading="loading" element-loading-text="数据加载中,请稍候...">
<el-table ref="tableRef" :data="tableData" row-key="id" @selection-change="handleSelectionChange"
@select="handleSelect" @select-all="handleSelectAll" style="width: 100%" :row-style="{ height: '52px' }">
<el-table-column type="selection" width="40" />
<el-table-column label="政令名称" width="720">
<template #default="scope">
<span class="title-item text-compact-bold" @click="handleClickToDetail(scope.row)">{{
scope.row.originalTitle
}}</span>
</template>
</el-table-column>
<el-table-column label="发布时间" width="120" class-name="date-column">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column label="发布机构">
<template #default="scope">
<span class="person-item text-compact" @click="handleOrgClick(scope.row)">{{ scope.row.organizationName
}}</span>
</template>
</el-table-column>
<el-table-column label="涉及领域" width="350" class-name="date-column">
<template #default="scope">
<div class="tag-box">
<AreaTag v-for="tag, index in scope.row.domains" :key="index" :tagName="tag" />
</div>
</template>
</el-table-column>
<el-table-column label="政令类型" width="100">
<template #default="scope">{{ scope.row.typeStr }}</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="data-main-box-footer">
<el-pagination background layout="prev, pager, next" :total="totalNum" v-model:current-page="currentPage"
:page-size="pageSize" @current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import ChartContainer from '../components/ChartContainer/index.vue'
import ChartHeader from '../components/ChartHeader/index.vue'
import ActiveTag from '../components/ActiveTag/index.vue'
import HeaderBtnBox from '../components/HeaderBtnBox/index.vue'
import LineChart from '../components/LineChart/index.vue'
import PieChart from '../components/PieChart/index.vue'
import BarChart from '../components/BarChart/index.vue'
import RaderChart from '../components/RadarChart/idnex.vue'
import SelectBox from '../components/SelectBox/index.vue'
import { useRoute } from "vue-router";
import router from '@/router'
import { search } from '@/api/comprehensiveSearch'
import { ElMessage } from 'element-plus'
import getDateRange from '@/utils/getDateRange'
import { getDepartmentList } from "@/api/decree/home";
const route = useRoute();
// 图表/数据
const isShowChart = ref(false)
// 点击切换数据/图表
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
if (isShowChart.value) {
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
// setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
if (curDemension.value === '发布时间') {
if (selectedTime.value === '按月度统计') {
curChartData.value = curDemensionItem.data
} else if (selectedTime.value === '按季度统计') {
curChartData.value = curDemensionItem.quatarData
} else {
curChartData.value = curDemensionItem.yearData
}
} else {
curChartData.value = curDemensionItem.data
}
// })
}
}
// 总计数据
const totalNum = ref(0)
// 统计维度列表
const staticsDemensionList = ref([
{
name: '发布时间',
active: true,
chartTypeList: ['折线图', '柱状图'],
chartTitle: '美国科技政令提出数量随时间变化趋势',
data: {
dataX: [],
dataY: []
},
quatarData: {
dataX: [],
dataY: []
},
yearData: {
dataX: [],
dataY: []
}
},
{
name: '科技领域',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '美国科技政令领域分布',
data: []
},
{
name: '发布机构',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '美国科技政令发布机构分布',
data: []
}
])
// 当前维度下的图表列表
const curChartTypeList = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTypeList
})
// 当前图表标题
const curChartTitle = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTitle
})
// 当前维度
const curDemension = ref('发布时间')
// 点击维度item
const handleClickDemensionItem = (val) => {
activeChart.value = ''
staticsDemensionList.value.forEach(item => {
item.active = false
})
val.active = true
curDemension.value = val.name
setTimeout(() => {
activeChart.value = val.chartTypeList[0]
if (curDemension.value === '发布时间' && selectedTime.value === '按年度统计') {
curChartData.value = val.yearData
} else if (curDemension.value === '发布时间' && selectedTime.value === '按季度统计') {
curChartData.value = val.quatarData
} else {
curChartData.value = val.data
}
})
}
// 时间图表 当前选择时间
const selectedTime = ref('按年度统计')
// 时间图表-时间列表
const timeList = ref([
{
label: '按年度统计',
value: '按年度统计'
},
{
label: '按季度统计',
value: '按季度统计'
},
{
label: '按月度统计',
value: '按月度统计'
},
])
const handleChangeTime = value => {
let curChart = activeChart.value
activeChart.value = ''
if (value === '按月度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].data
})
} else if (value === '按季度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].quatarData
})
} else {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].yearData
})
}
}
// 激活的标签列表
const activeTagList = computed(() => {
const arr = []
if (selectedArea.value && selectedArea.value !== '全部领域') {
arr.push(
{
tag: '科技领域',
name: selectedArea.value
}
)
}
if (selectedDate.value === '自定义') {
arr.push(
{
tag: '发布时间',
name: customTime.value.join('至')
}
)
}
if (selectedIns.value && selectedIns.value !== '全部机构') {
arr.push(
{
tag: '发布机构',
name: selectedIns.value
}
)
}
if (selectedDecreeType.value && selectedDecreeType.value !== '全部类型') {
arr.push(
{
tag: '政令类型',
name: selectedDecreeType.value
}
)
}
if (isInvolveCn.value) {
const involveStr = '涉华'
arr.push(
{
tag: '是否涉华',
name: involveStr
}
)
}
if (isInvolveTechnology.value) {
const involveStr = '科技相关'
arr.push(
{
tag: '科技相关',
name: involveStr
}
)
}
return arr
})
// 关闭当前标签
const handleCloseCurTag = (tag, index) => {
switch (tag.tag) {
case '科技领域':
selectedArea.value = '全部领域'
break
case '发布时间':
selectedDate.value = ''
customTime.value = []
break
case '发布机构':
selectedIns.value = '全部机构'
break
case '政令类型':
selectedDecreeType.value = '全部类型'
break
case '是否涉华':
isInvolveCn.value = false
break
case '科技相关':
isInvolveTechnology.value = false
break
}
// alert(tag.name)
// activeTagList.value.splice(index, 1)
}
const activeChart = ref('') // 当前激活的图表
// 切换当前图表
const handleSwitchActiveChart = val => {
activeChart.value = val.name
}
// 雷达图数据
const radarChartData = ref({
title: [
{
name: '航空航天',
max: 10
},
{
name: '先进制造',
max: 10
},
{
name: '量子科技',
max: 10
},
{
name: '人工智能',
max: 10
},
{
name: '新材料',
max: 10
},
{
name: '集成电路',
max: 10
},
],
data: [
{
name: "337调查",
value: [10, 5, 2, 8, 5, 7
]
},
{
name: "232调查",
value: [2, 5, 3, 8, 10, 2]
},
{
name: "301调查",
value: [5, 8, 2, 9, 1, 5]
}
]
}
)
// 数据- 是否全选
const isSelectedAll = ref(false)
// 批量操作-当前操作
const curOperation = ref('')
const operationList = ref([
{
name: 'aaa',
id: 'aaa'
},
{
name: 'bbb',
id: 'bbb'
},
{
name: 'ccc',
id: 'ccc'
},
])
// 科技领域
const areaPlaceHolder = ref('请选择领域')
const selectedArea = ref('全部领域')
const areaList = ref([
{
name: '全部领域',
id: '全部领域'
},
{
name: '人工智能',
id: '人工智能'
},
{
name: '生物科技',
id: '生物科技'
},
{
name: '新一代通信网络',
id: '新一代通信网络'
},
{
name: '量子科技',
id: '量子科技'
},
{
name: '新能源',
id: '新能源'
},
{
name: '集成电路',
id: '集成电路'
},
{
name: '海洋',
id: '海洋'
},
{
name: '先进制造',
id: '先进制造'
},
{
name: '新材料',
id: '新材料'
},
{
name: '航空航天',
id: '航空航天'
},
{
name: '太空',
id: '太空'
},
{
name: '深海',
id: '深海'
},
{
name: '极地',
id: '极地'
},
{
name: '核',
id: '核'
},
{
name: '其他',
id: '其他'
},
])
const handleSelectArea = (value) => {
selectedArea.value = value
}
// 提出时间
const DatePlaceHolder = ref('请选择时间')
const selectedDate = ref('')
const dateList = ref([
{
name: '自定义',
id: '自定义'
},
{
name: '近一年',
id: '近一年'
},
{
name: '近半年',
id: '近半年'
},
{
name: '近三月',
id: '近三月'
},
{
name: '近一月',
id: '近一月'
}
])
const customTime = ref([]) // 自定义时间
const handleCustomDate = value => {
customTime.value = value
}
const handleSelectDate = (value) => {
selectedDate.value = value
if (selectedDate.value !== '自定义') {
customTime.value = getDateRange(selectedDate.value)
}
}
// 发布机构
const insList = ref([
{
name: '全部机构',
id: '全部机构'
},
])
const selectedIns = ref('全部机构')
const insPlaceHolder = ref('请选择发布机构')
const handleSelectIns = value => {
selectedIns.value = value
}
const handleGetDeparmentList = async () => {
try {
// let { keyWord, pageNum, pageSize, day } = organizationInfo
const params = {
day: 365,
}
const res = await getDepartmentList(params);
console.log("机构列表", res);
if (res.code === 200) {
let arr = res.data.orgList.map(item => {
return {
name: item.orgName,
id: item.orgName
}
})
insList.value = [...insList.value, ...arr]
}
} catch (error) {
}
}
// 政令类型列表
const decreeTypeList = ref([
{
name: '全部类型',
id: '全部类型'
},
{
name: '行政命令',
id: '行政命令'
},
{
name: '备忘录',
id: '备忘录'
}
])
const selectedDecreeType = ref('全部类型')
const decreeTypePlaceHolder = ref('请选择政令类型')
const handleSelectDecreeType = value => {
selectedDecreeType.value = value
}
// 是否涉华
const isInvolveCn = ref(false)
// 是否科技相关
const isInvolveTechnology = ref(false)
// 清空条件
const handleClear = () => {
selectedArea.value = '全部领域'
selectedDate.value = ''
customTime.value = []
selectedIns.value = '全部机构'
selectedDecreeType.value = '全部类型'
isInvolveCn.value = false
isInvolveTechnology.value = false
ElMessage.success('已清空条件!')
}
// 确定
const handleConfirm = () => {
currentPage.value = 1
fetchTableData()
}
// 展开全部 / 收起
const isFolderAll = ref(false)
const handleSwitchFolderAll = () => {
isFolderAll.value = !isFolderAll.value
}
const tableRef = ref(null)
// 表格数据
const tableData = ref([
])
const releaseTimeList = ref([
{
label: "按发布时间倒序",
value: true
},
{
label: "按发布时间升序",
value: false
}
]);
const isSort = ref(true); // true 倒序 false 升序
const handlePxChange = val => {
fetchTableData()
};
const currentPage = ref(1);
const pageSize = ref(10)
// 存储选中的数据(跨页)[citation:3][citation:8]
const selectedMap = ref(new Map()) // 使用 Map 存储,key 为唯一 id
// 计算已选中的条数
const selectedCount = computed(() => selectedMap.value.size)
// 获取当前页表格数据(示例)
const fetchTableData = async () => {
// isSelectedAll.value = false
// selectedMap.value.clear()
loading.value = true
// 调用接口获取数据...
const params = {
page: currentPage.value,
size: pageSize.value,
// keyword: '',
type: 2, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
domains: selectedArea.value === '全部领域' ? null : [selectedArea.value],
proposedDateStart: customTime.value[0] ? customTime.value[0] : null,
proposedDateEnd: customTime.value[1] ? customTime.value[1] : null,
organizationName: selectedIns.value === '全部机构' ? null : selectedIns.value,
decreeType: selectedDecreeType.value === '全部类型' ? null : selectedDecreeType.value,
isInvolveCn: isInvolveCn.value ? 'Y' : null,
isTechRelated: isInvolveTechnology.value ? 'Y' : null,
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
tableData.value = res.data.records
totalNum.value = res.data.total
staticsDemensionList.value[0].data = {
dataX: Object.keys(res.data.aggregationsDate),
dataY: Object.values(res.data.aggregationsDate).map(value => Number(value))
}
staticsDemensionList.value[0].quatarData = {
dataX: Object.keys(res.data.aggregationsQuarter),
dataY: Object.values(res.data.aggregationsQuarter).map(value => Number(value))
}
staticsDemensionList.value[0].yearData = {
dataX: Object.keys(res.data.aggregationsYear),
dataY: Object.values(res.data.aggregationsYear).map(value => Number(value))
}
staticsDemensionList.value[1].data = Object.entries(res.data.aggregationsDomain).map(([key, value]) => ({
name: key,
value: Number(value)
}))
staticsDemensionList.value[2].data = Object.entries(res.data.aggregationsorganizationName).map(([key, value]) => ({
name: key,
value: Number(value)
}))
}
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
activeChart.value = ''
setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
curChartData.value = curDemensionItem.data
})
} catch (error) {
console.error(error);
} finally {
loading.value = false
}
// 数据加载后,回显已选中的行
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
}
const allData = ref([])
// 获取筛选条件下全部表格数据
const fetchAllData = async () => {
const params = {
page: 1,
size: 9999,
// keyword: '',
type: 2, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
domains: selectedArea.value === '全部领域' ? null : [selectedArea.value],
proposedDateStart: customTime.value[0],
proposedDateEnd: customTime.value[1],
organizationName: selectedIns.value === '全部机构' ? null : selectedIns.value,
decreeType: selectedDecreeType.value === '全部类型' ? null : selectedDecreeType.value,
isInvolveCn: isInvolveCn.value ? 'Y' : null,
isTechRelated: isInvolveTechnology.value ? 'Y' : null,
sort: isSort.value ? 0 : 1
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
allData.value = res.data.records
}
} catch (error) {
ElMessage.error('加载全部数据出错!')
}
}
// 单选事件
const handleSelect = (selection, row) => {
if (selection.some(item => item.id === row.id)) {
// 选中:添加到 Map
selectedMap.value.set(row.id, row)
} else {
// 取消选中:从 Map 移除
selectedMap.value.delete(row.id)
}
}
// 表格自带 当前页 全选/全不选事件
const handleSelectAll = (selection) => {
if (selection.length > 0) {
// 全选:将当前页所有数据添加到 Map
tableData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
} else {
// 全不选:从 Map 中移除当前页的所有数据
tableData.value.forEach(row => {
selectedMap.value.delete(row.id)
})
}
}
// 处理选择变化(用于统计)
const handleSelectionChange = (val) => {
// 这里可以做一些额外的处理,但主要统计使用 selectedMap
console.log('当前页选中数量:', val.length)
}
// 全选当前页按钮
const handleSelectAllPage = () => {
if (tableData.value.length === 0) return
// 检查当前页是否已全选
const currentPageSelected = tableData.value.every(row =>
selectedMap.value.has(row.id)
)
if (currentPageSelected) {
// 已全选,则不动当前页的全选
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, false)
// selectedMap.value.delete(row.id)
})
} else {
// 未全选,则全选当前页
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, true)
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
}
}
// 全选最大1万条提示
const isShowAllDataMaxLengthTip = ref(false)
const loading = ref(false) // 加载数据loading
// 处理 全选(全部数据)
const handleSelectAllChange = async () => {
if (isSelectedAll.value) {
if (totalNum.value > 10000) {
isShowAllDataMaxLengthTip.value = true
}
loading.value = true
await fetchAllData()
handleSelectAllPage()
allData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
loading.value = false
} else {
handleClearAll()
}
}
// 清空所有选择
const handleClearAll = () => {
isSelectedAll.value = false
selectedMap.value.clear()
tableRef.value?.clearSelection()
}
// 翻页
const handleCurrentChange = async (val) => {
currentPage.value = val
await fetchTableData()
if (isSelectedAll.value) {
handleSelectAllPage()
}
}
// 监听数据变化,回显选中状态 [citation:4][citation:8]
watch(tableData, () => {
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
})
// 当前图表数据
const curChartData = ref(null)
// 下载当前图表数据
const handleDownloadCurChartData = () => {
const jsonStr = JSON.stringify(curChartData.value, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'chartData.json';
link.click();
URL.revokeObjectURL(url);
}
// 跳转到当前页 初始化筛选条件
const initParam = () => {
const hasQuery = Object.keys(route.query).length > 0;
if (hasQuery) {
selectedArea.value = route.query.domains ? route.query.domains : '全部领域'
if (route.query.selectedDate && Array.isArray(JSON.parse(route.query.selectedDate)) && JSON.parse(route.query.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(route.query.selectedDate)
}
selectedIns.value = route.query.orgnizationName ? route.query.orgnizationName : '全部机构'
isInvolveCn.value = route.query.isInvolveCn ? true : false
isInvolveTechnology.value = route.query.isInvolveTechnology ? true : false
selectedDecreeType.value = route.query.selectedDecreeType ? route.query.selectedDecreeType : '全部类型'
const query = route.query;
if (Object.keys(query).length > 0) {
sessionStorage.setItem('decreeRouteQuery', JSON.stringify(query));
}
} else {
const savedQuery = JSON.parse(sessionStorage.getItem('decreeRouteQuery') || '{}');
selectedArea.value = savedQuery.domains ? savedQuery.domains : '全部领域'
if (savedQuery.selectedDate && Array.isArray(JSON.parse(savedQuery.selectedDate)) && JSON.parse(savedQuery.selectedDate).length) {
selectedDate.value = '自定义'
customTime.value = JSON.parse(savedQuery.selectedDate)
}
isInvolveCn.value = savedQuery.isInvolveCn ? true : false
isInvolveTechnology.value = savedQuery.isInvolveTechnology ? true : false
selectedDecreeType.value = savedQuery.selectedDecreeType ? savedQuery.selectedDecreeType : '全部类型'
}
}
// 跳转政令详情
const handleClickToDetail = (curDecree) => {
console.log('curDecree', curDecree);
window.sessionStorage.setItem("decreeId", curDecree.id);
window.sessionStorage.setItem("curTabName", curDecree.title);
const route = router.resolve({
path: "/decreeLayout",
query: {
id: curDecree.id
}
});
window.open(route.href, "_blank");
};
// 跳转机构详情
const handleOrgClick = item => {
console.log('item', item);
window.sessionStorage.setItem("curTabName", item.organizationName);
const route = router.resolve({
path: "/institution",
query: {
id: item.organizationId
}
});
window.open(route.href, "_blank");
};
// 导出
const handleExport = () => {
if (!selectedCount.value) {
ElMessage.warning('请选择至少一项数据!')
return
}
console.log(selectedMap.value);
const arr = Array.from(selectedMap.value);
const jsonStr = JSON.stringify(arr, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'export.json';
link.click();
URL.revokeObjectURL(url);
};
onMounted(async () => {
handleGetDeparmentList()
initParam()
// 初始化
await fetchTableData()
})
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
overflow: hidden;
overflow-y: auto;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
min-height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
box-sizing: border-box;
padding: 16px 24px;
.header-top {
min-height: 28px;
display: flex;
flex-wrap: wrap;
gap: 12px 42px;
// transition: all ease 1s;
.check-box {
display: flex;
width: 348px;
height: 28px;
align-items: center;
gap: 8px;
.check-box-left {
width: 100px;
color: var(--text-primary-65-color);
}
}
}
.header-footer {
margin-top: 16px;
display: flex;
justify-content: space-between;
.header-footer-left {
display: flex;
justify-content: space-between;
gap: 8px;
}
}
}
.chart-main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
.content-header {
margin: 16px 24px;
width: 1520px;
height: 28px;
}
.content-main {
width: 1520px;
margin: 0 auto;
}
}
}
.data-main-box {
width: 1568px;
min-height: 810px;
border-radius: 10px;
background: var(--bg-white-100);
margin: 0 auto;
margin-bottom: 20px;
overflow: hidden;
.data-main-box-header {
margin: 16px auto;
width: 1520px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
box-sizing: border-box;
padding: 2px 0;
color: var(--color-red-100);
}
}
.data-main-box-main {
width: 1520px;
// height: 633px;
min-height: 680px;
border-radius: 10px;
border: 1px solid var(--bg-black-5);
margin: 0 auto;
.data-main-box-main-header {
height: 48px;
background: var(--bg-black-2);
display: flex;
justify-content: space-between;
.header-left {
margin-left: 16px;
height: 48px;
display: flex;
gap: 16px;
align-items: center;
.header-left-item2 {
color: var(--color-primary-100);
display: flex;
gap: 8px;
}
.header-left-item3 {
color: var(--color-orange-100);
}
.cancel {
cursor: pointer;
}
}
.header-right {
margin-right: 16px;
display: flex;
gap: 8px;
align-items: center;
.header-right-item {
height: 30px;
padding: 5px 16px;
border: 1px solid var(--bg-black-10);
border-radius: 4px;
background: var(--bg-white-100);
cursor: pointer;
}
.item1 {
display: flex;
gap: 2px;
justify-content: center;
align-items: center;
&:hover {
background: var(--color-primary-2);
}
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
color: var(--text-primary-65-color);
}
}
.item2 {}
.item3 {}
}
}
.data-main-box-main-content {}
}
.data-main-box-footer {
margin: 16px auto 0;
height: 40px;
width: 1520px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
.date-column {
background-color: #ecf5ff;
.tag-box {
display: flex;
flex-wrap: wrap;
gap: 8px;
width: 340px;
}
}
.date-column .cell {
color: #409eff !important;
font-weight: 500;
}
.title-item {
color: var(--text-primary-80-color);
cursor: pointer;
&:hover {
color: var(--color-primary-100);
text-decoration: underline;
}
}
.person-item {
color: var(--color-primary-100);
cursor: pointer;
&:hover {
font-weight: bold;
text-decoration: underline;
}
}
:deep(.el-table__header-wrapper) {
// background-color: #f5f7fa;
height: 48px;
}
:deep(.el-table__header th) {
// background-color: #f5f7fa;
color: var(--text-primary-50-color);
font-weight: bold;
}
/* 针对特定列 */
// :deep(.el-table__header th:first-child) {
// background-color: #e6f7ff;
// color: #1890ff;
// }</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">我是国会议员</div>
<div class="main-box">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img v-if="!isShowChart" src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
<img v-else src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box"></div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 图表/数据
const isShowChart = ref(true)
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
}
// 总计数据
const totalNum = ref(12)
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
}
}
}
</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">
<div class="header-top">
<SelectBox :placeholder-name="personTypePlaceHolder" select-title="人物类别" :select-list="personTypeList"
:select-name="selectedPersonType" @update:select-text="handlePersonType" />
<SelectBox :placeholder-name="nationalityPlaceHolder" select-title="人物国籍" :select-list="nationalityList"
:select-name="selectedNationality" @update:select-text="handleSelectNationality" />
<SelectBox :placeholder-name="insPlaceHolder" select-title="所属机构" :select-list="insList"
:select-name="selectedIns" @update:select-text="handleSelectIns" />
<SelectBox :placeholder-name="partyPlaceHolder" select-title="党派" :select-list="partyList"
:select-name="selectedParty" @update:select-text="handleSelectParty" />
</div>
<div class="header-footer">
<div class="header-footer-left">
<ActiveTag v-for="tag, index in activeTagList" :key="index" :tagName="tag.name"
@close="handleCloseCurTag(tag, index)" />
</div>
<div class="header-footer-right">
<HeaderBtnBox :isShowAll="isFolderAll" :isShowAllBtn="false" @show-all="handleSwitchFolderAll"
@clear="handleClear" @confirm="handleConfirm" />
</div>
</div>
</div>
<div class="chart-main-box" v-if="isShowChart">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box">
<div class="content-header">
<ChartHeader :list="staticsDemensionList" @clickItem="handleClickDemensionItem">
<template #chart-header-right>
<el-select v-model="selectedTime" placeholder="选择时间" style="width: 150px" v-show="curDemension === '发布时间'"
@change="handleChangeTime">
<el-option v-for="item in timeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</ChartHeader>
</div>
<div class="content-main">
<ChartContainer :chartTitle="curChartTitle" :chartTypeList="curChartTypeList"
@clickChartItem="handleSwitchActiveChart" @download="handleDownloadCurChartData">
<template #chart-box>
<LineChart v-if="activeChart === '折线图'" :lineChartData="curChartData" />
<BarChart v-if="activeChart === '柱状图'" :barChartData="curChartData" />
<PieChart v-if="activeChart === '饼状图'" :pieChartData="curChartData" />
<RaderChart v-if="activeChart === '雷达图'" :radarChartData="curChartData" />
</template>
</ChartContainer>
</div>
</div>
</div>
<div class="data-main-box" v-else>
<div class="data-main-box-header">
<div class="switch-box" @click="handleSwitchChartData">
<img src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="data-main-box-main">
<div class="data-main-box-main-header">
<div class="header-left">
<div class="header-left-item1">
<el-checkbox v-model="isSelectedAll" label="全选" @change="handleSelectAllChange" size="large" />
</div>
<div class="header-left-item2 text-tip-1">{{ `已选择${selectedCount}项` }}</div>
<div class="header-left-item2 text-tip-1 cancel" @click="handleClearAll" v-show="selectedCount">{{ '取消' }}
<div class="header-left-item3 text-tip-1" v-if="isShowAllDataMaxLengthTip">{{ `(当前最大选择不能超过1万条!)` }}</div>
</div>
</div>
<div class="header-right">
<div class="header-right-item item1" @click="handleExport">
<div class="icon">
<img src="../assets/icons/download.svg" alt="">
</div>
<div class="text text-tip-1">{{ '导出' }}</div>
</div>
<div class="header-right-item2 item2">
<el-select v-model="curOperation" placeholder="批量操作" style="width: 120px">
<el-option v-for="item in operationList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div class="header-right-item3 item3">
<el-select v-model="isSort" placeholder="发布时间" style="width: 166px" @change="handlePxChange">
<template #prefix>
<div style="display: flex; align-items: center; height: 100%">
<img src="../assets/icons/desc-icon.svg" style="width: 14px; height: 14px" />
</div>
</template>
<el-option v-for="item in releaseTimeList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
</div>
</div>
<div class="data-main-box-main-content" v-loading="loading" element-loading-text="数据加载中,请稍候...">
<el-table ref="tableRef" :data="tableData" row-key="id" @selection-change="handleSelectionChange"
@select="handleSelect" @select-all="handleSelectAll" style="width: 100%" :row-style="{ height: '52px' }">
<el-table-column type="selection" width="40" />
<el-table-column label="人物名称" width="540">
<template #default="scope">
<span class="title-item text-compact-bold" @click="handleClickToDetail(scope.row)">{{
scope.row.originalTitle
}}</span>
</template>
</el-table-column>
<el-table-column label="时间" width="120" class-name="date-column">
<template #default="scope">{{ scope.row.date }}</template>
</el-table-column>
<el-table-column label="所属机构">
<template #default="scope">
<span class="person-item text-compact" @click="handleOrgClick(scope.row)">{{ scope.row.organizationName
}}</span>
</template>
</el-table-column>
<el-table-column label="党派" width="100">
<template #default="scope">{{ scope.row.affiliation }}</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="data-main-box-footer">
<el-pagination background layout="prev, pager, next" :total="totalNum" v-model:current-page="currentPage"
:page-size="pageSize" @current-change="handleCurrentChange" />
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import ChartContainer from '../components/ChartContainer/index.vue'
import ChartHeader from '../components/ChartHeader/index.vue'
import ActiveTag from '../components/ActiveTag/index.vue'
import HeaderBtnBox from '../components/HeaderBtnBox/index.vue'
import LineChart from '../components/LineChart/index.vue'
import PieChart from '../components/PieChart/index.vue'
import BarChart from '../components/BarChart/index.vue'
import RaderChart from '../components/RadarChart/idnex.vue'
import SelectBox from '../components/SelectBox/index.vue'
import { useRoute } from "vue-router";
import router from '@/router'
import { search } from '@/api/comprehensiveSearch'
import { ElMessage } from 'element-plus'
import { getPersonType, getCountryList, getThinkTankList } from "@/api/comprehensiveSearch/index"
const route = useRoute();
// 图表/数据
const isShowChart = ref(false)
// 点击切换数据/图表
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
if (isShowChart.value) {
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
activeChart.value = curDemensionItem.chartTypeList[0]
curChartData.value = curDemensionItem.data
}
}
// 总计数据
const totalNum = ref(0)
// 统计维度列表
const staticsDemensionList = ref([
{
name: '人物国籍',
active: true,
chartTypeList: ['饼状图'],
chartTitle: '科技人物国籍分布',
data: []
},
{
name: '党派',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '科技人物党派分布',
data: []
},
{
name: '所属机构',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '科技人物所属机构分布',
data: []
},
{
name: '人物类别',
active: false,
chartTypeList: ['饼状图'],
chartTitle: '科技人物类别分布',
data: []
},
])
// 当前维度下的图表列表
const curChartTypeList = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTypeList
})
// 当前图表标题
const curChartTitle = computed(() => {
let arr = staticsDemensionList.value.filter(item => item.active)
return arr[0].chartTitle
})
// 当前维度
const curDemension = ref('人物国籍')
// 点击维度item
const handleClickDemensionItem = (val) => {
activeChart.value = ''
staticsDemensionList.value.forEach(item => {
item.active = false
})
val.active = true
nextTick(() => {
activeChart.value = val.chartTypeList[0]
curChartData.value = val.data
curDemension.value = val.name
})
}
// 时间图表 当前选择时间
const selectedTime = ref('按年度统计')
// 时间图表-时间列表
const timeList = ref([
{
label: '按年度统计',
value: '按年度统计'
},
{
label: '按季度统计',
value: '按季度统计'
},
{
label: '按月度统计',
value: '按月度统计'
},
])
const handleChangeTime = value => {
let curChart = activeChart.value
activeChart.value = ''
if (value === '按月度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].data
})
} else if (value === '按季度统计') {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].quatarData
})
} else {
setTimeout(() => {
activeChart.value = curChart
curChartData.value = staticsDemensionList.value[0].yearData
})
}
}
// 激活的标签列表
const activeTagList = computed(() => {
const arr = []
if (selectedPersonType.value && selectedPersonType.value !== '全部人物类别') {
arr.push(
{
tag: '人物类别',
name: selectedPersonType.value
}
)
}
if (selectedNationality.value && selectedNationality.value !== '全部人物国籍') {
let nationalityStr = nationalityList.value.filter(item => item.id === selectedNationality.value)[0]?.name
arr.push(
{
tag: '人物国籍',
name: nationalityStr
}
)
}
if (selectedIns.value && selectedIns.value !== '全部机构') {
arr.push(
{
tag: '所属机构',
name: selectedIns.value
}
)
}
if (selectedParty.value && selectedParty.value !== '全部党派') {
arr.push(
{
tag: '党派',
name: selectedParty.value
}
)
}
return arr
})
// 关闭当前标签
const handleCloseCurTag = (tag, index) => {
switch (tag.tag) {
case '人物类别':
selectedPersonType.value = '全部人物类别'
break
case '人物国籍':
selectedNationality.value = '全部人物国籍'
break
case '所属机构':
selectedIns.value = '全部机构'
break
case '党派':
selectedParty.value = '全部党派'
break
}
}
const activeChart = ref('') // 当前激活的图表
// 切换当前图表
const handleSwitchActiveChart = val => {
activeChart.value = val.name
}
// 数据- 是否全选
const isSelectedAll = ref(false)
// 批量操作-当前操作
const curOperation = ref('')
const operationList = ref([
])
// 人物类别
const personTypePlaceHolder = ref('请选择人物类别')
const selectedPersonType = ref('全部人物类别')
const personTypeList = ref([
{
name: '全部人物类别',
id: '全部人物类别'
}
])
const handlePersonType = (value) => {
selectedPersonType.value = value
}
// 获取人物类别
const handleGetPersonType = async () => {
try {
const res = await getPersonType()
console.log('人物类别', res);
if (res && res.length) {
personTypeList.value = res.map(item => {
return {
name: item,
id: item
}
})
personTypeList.value = [
{
name: '全部人物类别',
id: '全部人物类别'
},
...personTypeList.value
]
}
} catch (error) {
console.error(error);
}
}
// 国籍
const nationalityPlaceHolder = ref('请选择人物国籍')
const selectedNationality = ref('全部人物国籍')
const nationalityList = ref([
{
name: '全部人物国籍',
id: '全部人物国籍'
},
])
const handleSelectNationality = (value) => {
selectedNationality.value = value
}
// 获取国籍列表
const handleGetCountryList = async () => {
try {
const res = await getCountryList()
console.log('国籍列表', res);
if (res.code === 200 && res.data) {
nationalityList.value = res.data.map(item => {
return {
name: item.name,
id: item.id
}
})
nationalityList.value = [
{
name: '全部人物国籍',
id: '全部人物国籍'
},
...nationalityList.value
]
}
} catch (error) {
console.error(error);
}
}
// 所属机构
const insList = ref([
{
name: '全部机构',
id: '全部机构'
},
])
const selectedIns = ref('全部机构')
const insPlaceHolder = ref('请选择所属机构')
const handleSelectIns = value => {
selectedIns.value = value
}
// 获取所属机构列表
const handleGetInsList = async () => {
const params = {
type: 6
}
try {
const res = await getThinkTankList(params)
console.log('所属机构列表', res);
if (res && res.length) {
insList.value = res.map(item => {
return {
name: item,
id: item
}
})
insList.value = [
{
name: '全部机构',
id: '全部机构'
},
...insList.value
]
}
} catch (error) {
console.error(error);
}
}
// 党派列表
const partyList = ref([
{
name: '全部党派',
id: '全部党派'
},
{
name: '民主党',
id: '民主党'
},
{
name: '共和党',
id: '共和党'
},
])
const selectedParty = ref('全部党派')
const partyPlaceHolder = ref('请选择党派')
const handleSelectParty = value => {
selectedParty.value = value
}
// 清空条件
const handleClear = () => {
selectedPersonType.value = '全部人物类别'
selectedNationality.value = '全部人物国籍'
selectedIns.value = '全部机构'
selectedParty.value = '全部党派'
ElMessage.success('已清空条件!')
}
// 确定
const handleConfirm = () => {
currentPage.value = 1
fetchTableData()
}
// 展开全部 / 收起
const isFolderAll = ref(false)
const handleSwitchFolderAll = () => {
isFolderAll.value = !isFolderAll.value
}
const tableRef = ref(null)
// 表格数据
const tableData = ref([
])
const releaseTimeList = ref([
{
label: "按发布时间倒序",
value: true
},
{
label: "按发布时间升序",
value: false
}
]);
const isSort = ref(true); // true 倒序 false 升序
const handlePxChange = val => {
fetchTableData()
};
const currentPage = ref(1);
const pageSize = ref(10)
// 存储选中的数据(跨页)[citation:3][citation:8]
const selectedMap = ref(new Map()) // 使用 Map 存储,key 为唯一 id
// 计算已选中的条数
const selectedCount = computed(() => selectedMap.value.size)
// 获取当前页表格数据(示例)
const fetchTableData = async () => {
// isSelectedAll.value = false
// selectedMap.value.clear()
loading.value = true
// 调用接口获取数据...
const params = {
page: currentPage.value,
size: pageSize.value,
type: 6, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
countryId: selectedNationality.value === '全部人物国籍' ? null : selectedNationality.value,
personType: selectedPersonType.value === '全部人物类别' ? null : selectedPersonType.value,
organizationName: selectedIns.value === '全部机构' ? null : selectedIns.value,
affiliation: selectedParty.value === '全部党派' ? null : selectedParty.value,
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
tableData.value = res.data.records
totalNum.value = res.data.total
staticsDemensionList.value[0].data = Object.entries(res.data.aggregationCountryId).map(([key, value]) => ({
name: key,
value: Number(value)
}))
staticsDemensionList.value[1].data = Object.entries(res.data.aggregationsAffiliation).map(([key, value]) => ({
name: key,
value: Number(value)
}))
staticsDemensionList.value[2].data = Object.entries(res.data.aggregationsorganizationName).map(([key, value]) => ({
name: key,
value: Number(value)
}))
}
const curDemensionItem = staticsDemensionList.value.filter(item => {
return item.name === curDemension.value
})[0]
activeChart.value = ''
setTimeout(() => {
activeChart.value = curDemensionItem.chartTypeList[0]
curChartData.value = curDemensionItem.data
})
} catch (error) {
console.error(error);
} finally {
loading.value = false
}
// 数据加载后,回显已选中的行
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
}
const allData = ref([])
// 获取筛选条件下全部表格数据
const fetchAllData = async () => {
const params = {
page: 1,
size: 9999,
type: 6, // type 1= 法案 2= 政令 3 =智库 4=智库报告 5=实体清单【制裁记录】 6= 人物 7= 机构 8=新闻 9= 社媒
countryId: selectedNationality.value === '全部人物国籍' ? null : selectedNationality.value,
personType: selectedPersonType.value === '全部人物类别' ? null : selectedPersonType.value,
organizationName: selectedIns.value === '全部机构' ? null : selectedIns.value,
affiliation: selectedParty.value === '全部党派' ? null : selectedParty.value,
sort: isSort.value ? 0 : 1 // 0 先按分数降序 后按时间降序 1 先按分数降序,再按时间升序
}
try {
const res = await search(params)
console.log('搜索结果', res);
if (res.code === 200 && res.data) {
allData.value = res.data.records
}
} catch (error) {
ElMessage.error('加载全部数据出错!')
}
}
// 单选事件
const handleSelect = (selection, row) => {
if (selection.some(item => item.id === row.id)) {
// 选中:添加到 Map
selectedMap.value.set(row.id, row)
} else {
// 取消选中:从 Map 移除
selectedMap.value.delete(row.id)
}
}
// 表格自带 当前页 全选/全不选事件
const handleSelectAll = (selection) => {
if (selection.length > 0) {
// 全选:将当前页所有数据添加到 Map
tableData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
} else {
// 全不选:从 Map 中移除当前页的所有数据
tableData.value.forEach(row => {
selectedMap.value.delete(row.id)
})
}
}
// 处理选择变化(用于统计)
const handleSelectionChange = (val) => {
// 这里可以做一些额外的处理,但主要统计使用 selectedMap
console.log('当前页选中数量:', val.length)
}
// 全选当前页按钮
const handleSelectAllPage = () => {
if (tableData.value.length === 0) return
// 检查当前页是否已全选
const currentPageSelected = tableData.value.every(row =>
selectedMap.value.has(row.id)
)
if (currentPageSelected) {
// 已全选,则不动当前页的全选
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, false)
// selectedMap.value.delete(row.id)
})
} else {
// 未全选,则全选当前页
tableData.value.forEach(row => {
tableRef.value.toggleRowSelection(row, true)
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
}
}
// 全选最大1万条提示
const isShowAllDataMaxLengthTip = ref(false)
const loading = ref(false) // 加载数据loading
// 处理 全选(全部数据)
const handleSelectAllChange = async () => {
if (isSelectedAll.value) {
if (totalNum.value > 10000) {
isShowAllDataMaxLengthTip.value = true
}
loading.value = true
await fetchAllData()
handleSelectAllPage()
allData.value.forEach(row => {
if (!selectedMap.value.has(row.id)) {
selectedMap.value.set(row.id, row)
}
})
loading.value = false
} else {
handleClearAll()
}
}
// 清空所有选择
const handleClearAll = () => {
isSelectedAll.value = false
selectedMap.value.clear()
tableRef.value?.clearSelection()
}
// 翻页
const handleCurrentChange = async (val) => {
currentPage.value = val
await fetchTableData()
if (isSelectedAll.value) {
handleSelectAllPage()
}
}
// 监听数据变化,回显选中状态 [citation:4][citation:8]
watch(tableData, () => {
nextTick(() => {
tableData.value.forEach(row => {
if (selectedMap.value.has(row.id)) {
tableRef.value?.toggleRowSelection(row, true)
}
})
})
})
// 当前图表数据
const curChartData = ref(null)
// 下载当前图表数据
const handleDownloadCurChartData = () => {
const jsonStr = JSON.stringify(curChartData.value, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'chartData.json';
link.click();
URL.revokeObjectURL(url);
}
// 跳转到当前页 初始化筛选条件
const initParam = () => {
const hasQuery = Object.keys(route.query).length > 0;
if (hasQuery) {
selectedPersonType.value = route.query.domains ? route.query.domains : '全部人物类别'
selectedIns.value = route.query.orgnizationName ? route.query.orgnizationName : '全部机构'
selectedParty.value = route.query.selectedParty ? route.query.selectedParty : '全部党派'
const query = route.query;
if (Object.keys(query).length > 0) {
sessionStorage.setItem('decreeRouteQuery', JSON.stringify(query));
}
} else {
const savedQuery = JSON.parse(sessionStorage.getItem('decreeRouteQuery') || '{}');
selectedPersonType.value = savedQuery.domains ? savedQuery.domains : '全部人物类别'
selectedParty.value = savedQuery.selectedParty ? savedQuery.selectedParty : '全部党派'
}
}
// 跳转人物详情
const handleClickToDetail = (item) => {
window.sessionStorage.setItem('curTabName', item.name)
const routeData = router.resolve({
path: "/characterPage",
query: {
personId: item.id
}
});
window.open(routeData.href, "_blank");
};
// 跳转机构详情
const handleOrgClick = item => {
console.log('item', item);
window.sessionStorage.setItem("curTabName", item.organizationName);
const route = router.resolve({
path: "/institution",
query: {
id: item.organizationId
}
});
window.open(route.href, "_blank");
};
// 导出
const handleExport = () => {
if (!selectedCount.value) {
ElMessage.warning('请选择至少一项数据!')
return
}
console.log(selectedMap.value);
const arr = Array.from(selectedMap.value);
const jsonStr = JSON.stringify(arr, null, 2);
const blob = new Blob([jsonStr], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'export.json';
link.click();
URL.revokeObjectURL(url);
};
onMounted(async () => {
await handleGetCountryList() // 获取国籍列表
await handleGetInsList()
await handleGetPersonType()
initParam()
// 初始化
await fetchTableData()
})
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
overflow: hidden;
overflow-y: auto;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
min-height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
box-sizing: border-box;
padding: 16px 24px;
.header-top {
min-height: 28px;
display: flex;
flex-wrap: wrap;
gap: 12px 42px;
// transition: all ease 1s;
.check-box {
display: flex;
width: 348px;
height: 28px;
align-items: center;
gap: 8px;
.check-box-left {
width: 100px;
color: var(--text-primary-65-color);
}
}
}
.header-footer {
margin-top: 16px;
display: flex;
justify-content: space-between;
.header-footer-left {
display: flex;
justify-content: space-between;
gap: 8px;
}
}
}
.chart-main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
.content-header {
margin: 16px 24px;
width: 1520px;
height: 28px;
}
.content-main {
width: 1520px;
margin: 0 auto;
}
}
}
.data-main-box {
width: 1568px;
min-height: 810px;
border-radius: 10px;
background: var(--bg-white-100);
margin: 0 auto;
margin-bottom: 20px;
overflow: hidden;
.data-main-box-header {
margin: 16px auto;
width: 1520px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
box-sizing: border-box;
padding: 2px 0;
color: var(--color-red-100);
}
}
.data-main-box-main {
width: 1520px;
// height: 633px;
min-height: 680px;
border-radius: 10px;
border: 1px solid var(--bg-black-5);
margin: 0 auto;
.data-main-box-main-header {
height: 48px;
background: var(--bg-black-2);
display: flex;
justify-content: space-between;
.header-left {
margin-left: 16px;
height: 48px;
display: flex;
gap: 16px;
align-items: center;
.header-left-item2 {
color: var(--color-primary-100);
display: flex;
gap: 8px;
}
.header-left-item3 {
color: var(--color-orange-100);
}
.cancel {
cursor: pointer;
}
}
.header-right {
margin-right: 16px;
display: flex;
gap: 8px;
align-items: center;
.header-right-item {
height: 30px;
padding: 5px 16px;
border: 1px solid var(--bg-black-10);
border-radius: 4px;
background: var(--bg-white-100);
cursor: pointer;
}
.item1 {
display: flex;
gap: 2px;
justify-content: center;
align-items: center;
&:hover {
background: var(--color-primary-2);
}
.icon {
width: 16px;
height: 16px;
img {
width: 100%;
height: 100%;
}
}
.text {
color: var(--text-primary-65-color);
}
}
.item2 {}
.item3 {}
}
}
.data-main-box-main-content {}
}
.data-main-box-footer {
margin: 16px auto 0;
height: 40px;
width: 1520px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
.date-column {
background-color: #ecf5ff;
.tag-box {
display: flex;
flex-wrap: wrap;
gap: 8px;
width: 340px;
}
}
.date-column .cell {
color: #409eff !important;
font-weight: 500;
}
.title-item {
color: var(--text-primary-80-color);
cursor: pointer;
&:hover {
color: var(--color-primary-100);
text-decoration: underline;
}
}
.person-item {
color: var(--color-primary-100);
cursor: pointer;
&:hover {
font-weight: bold;
text-decoration: underline;
}
}
:deep(.el-table__header-wrapper) {
// background-color: #f5f7fa;
height: 48px;
}
:deep(.el-table__header th) {
// background-color: #f5f7fa;
color: var(--text-primary-50-color);
font-weight: bold;
}
/* 针对特定列 */
// :deep(.el-table__header th:first-child) {
// background-color: #e6f7ff;
// color: #1890ff;
// }</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">我是机构主官</div>
<div class="main-box">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img v-if="!isShowChart" src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
<img v-else src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box"></div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 图表/数据
const isShowChart = ref(true)
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
}
// 总计数据
const totalNum = ref(12)
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
}
}
}
</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">我是科技企业领袖</div>
<div class="main-box">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img v-if="!isShowChart" src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
<img v-else src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box"></div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 图表/数据
const isShowChart = ref(true)
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
}
// 总计数据
const totalNum = ref(12)
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
}
}
}
</style>
\ No newline at end of file
<template>
<div class="countrybill-wrapper">
<div class="header-box">我是智库研究人员</div>
<div class="main-box">
<div class="info-box">
<div class="switch-box" @click="handleSwitchChartData">
<img v-if="!isShowChart" src="@/views/dataLibrary/assets/icons/chart-active.svg" alt="">
<img v-else src="@/views/dataLibrary/assets/icons/data-active.svg" alt="">
</div>
<div class="num-box text-title-3-bold">
{{ `共 ${totalNum} 条数据` }}
</div>
</div>
<div class="content-box"></div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 图表/数据
const isShowChart = ref(true)
const handleSwitchChartData = () => {
isShowChart.value = !isShowChart.value
}
// 总计数据
const totalNum = ref(12)
</script>
<style lang="scss" scoped>
.countrybill-wrapper {
width: 1600px;
height: 968px;
.headere-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.header-box {
width: 1568px;
height: 112px;
border-radius: 10px;
background: rgb(255, 255, 255);
border: 1px solid var(--bg-black-5);
margin: 16px auto;
}
.main-box {
.info-box {
margin: 0 auto;
width: 1568px;
height: 30px;
display: flex;
justify-content: space-between;
.switch-box {
width: 160px;
border-radius: 20px;
border: 1px solid var(--color-primary-100);
height: 30px;
cursor: pointer;
img {
width: 100%;
height: 100%;
}
}
.num-box {
color: var(--color-red-100);
}
}
.content-box {
margin: 0 auto;
margin-top: 16px;
width: 1568px;
height: 766px;
border-radius: 10px;
background: rgba(255, 255, 255);
border: 1px solid var(--bg-black-5);
}
}
}
</style>
\ No newline at end of file
......@@ -570,8 +570,11 @@ const handleSelectThinkTank = value => {
};
const handleGetThinkTankList = async () => {
const params = {
type: 4
}
try {
const res = await getThinkTankList();
const res = await getThinkTankList(params);
console.log("智库列表", res);
let arr = res.map(item => {
return {
......
......@@ -75,6 +75,8 @@ import title01 from './assets/title01.png'
import title02 from './assets/title02.png'
import title03 from './assets/title03.png'
import { getNews, getRemarks } from '@/api/ruleRestriction/index.js'
import { useGotoNewsDetail } from "@/router/modules/news";
const gotoNewsDetail = useGotoNewsDetail();
const leftList = ref([]);
const rightList = ref([]);
......@@ -119,13 +121,7 @@ const handleToMoreNews = () => {
};
// 查看新闻资讯详情
const handleToNewsDetail = item => {
const route = router.resolve({
path: "/newsAnalysis",
query: {
newsId: item.id
}
});
window.open(route.href, "_blank");
gotoNewsDetail(item.id);
};
// 查看社交媒体详情
......
......@@ -2276,17 +2276,6 @@ const handleClickPerson = async item => {
} catch (error) { }
};
// 点击新闻条目,跳转到新闻分析页
const handleToNewsAnalysis = news => {
const route = router.resolve({
path: "/newsAnalysis",
query: {
newsId: news.newsId
}
});
window.open(route.href, "_blank");
};
const handleToReportDetail = item => {
window.sessionStorage.setItem("curTabName", item.name);
const route = router.resolve({
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论