提交 351ae3b2 authored 作者: yanpeng's avatar yanpeng

exportControl 修改

上级 bb9c644a
......@@ -3,66 +3,65 @@ import request from "@/api/request.js";
// 中美博弈概览V2:最新风险动态统计
export function getLatestRiskUpdates(params) {
return request({
method: 'GET',
method: "GET",
url: `/api/rivalryIndexV2/LatestRiskUpdates`,
params: params
})
});
}
// 中美博弈概览V2:最新风险信号
export function getLatestRisks() {
return request({
method: 'GET',
url: `/api/rivalryIndexV2/LatestRisks`,
})
method: "GET",
url: `/api/rivalryIndexV2/LatestRisks`
});
}
// 中美博弈概览V2:美对华制裁措施数量趋势
export function geDomainContainmentTrend(params) {
return request({
method: 'GET',
method: "GET",
url: `/api/rivalryIndexV2/DomainContainmentTrend`,
params: params
})
});
}
// 中美博弈概况:获取榜单字典
export function getChartDict() {
return request({
method: 'GET',
url: `/api/union/summary/chartDict`,
})
method: "GET",
url: `/api/union/summary/chartDict`
});
}
// 根据字典信息,获取年份信息
export function getYearDict(id) {
return request({
method: "GET",
url: `/api/union/summary/chartYear/${id}`
});
}
// 中美博弈概况:中美科技实力对比
export function getCompare(id) {
export function getCompare(id, year) {
return request({
method: 'GET',
url: `/api/union/summary/compare/${id}`,
})
method: "GET",
url: `/api/union/summary/compare/${id}/${year}`
});
}
// 中美博弈分析
export function getTechnologyGameAnalysis() {
return request({
method: 'GET',
url: `/api/rivalryIndexV2/TechnologyGameAnalysis`,
})
method: "GET",
url: `/api/rivalryIndexV2/TechnologyGameAnalysis`
});
}
//中美博弈概览V7:美国政府部门对华制裁最新动态
export function getGovernmentSanctionsDynamics() {
return request({
method: 'GET',
url: `/api/rivalryIndex/governmentSanctionsDynamics`,
})
method: "GET",
url: `/api/rivalryIndex/governmentSanctionsDynamics`
});
}
......@@ -18,6 +18,15 @@
>
<el-option :value="value.id" :label="value.name" v-for="(value, index) in originList" :key="index" />
</el-select>
<el-select
class="select-item"
size="default"
style="margin-left: 15px; width: 200px; height: 32px"
v-model="year"
@change="handleGetCompare()"
>
<el-option :value="value" :label="value" v-for="(value, index) in yearList" :key="index" />
</el-select>
</div>
</div>
<div style="display: flex; height: 650px; width: 100%; padding-top: 12px">
......@@ -237,7 +246,7 @@ import Echarts from "@/components/Chart/index.vue";
import mockData from "./mock.json";
import radarChart from "./radarChart3.js";
import { getCompare, getChartDict, getTechnologyGameAnalysis } from "@/api/zmOverview/risk/index.js";
import { getCompare, getChartDict, getYearDict, getTechnologyGameAnalysis } from "@/api/zmOverview/risk/index.js";
import icon1 from "./icon/btn-icon-0.png";
import icon2 from "./icon/btn-icon-1.png";
import icon3 from "./icon/btn-icon-2.png";
......@@ -351,10 +360,27 @@ const handleGetChartDict = async () => {
console.error("获取数据来源error", error);
}
};
const yearList = ref([]);
const year = ref("");
//年份
const handleGetYearDict = async () => {
try {
const res = await getYearDict(origin.value);
console.log("年份", res);
if (res.code === 200 && res.data) {
yearList.value = res.data;
year.value = res.data[0];
}
} catch (error) {
console.error("获取年份error", error);
}
};
//中美科技实力对比
const handleGetCompare = async () => {
try {
const res = await getCompare(origin.value);
const res = await getCompare(origin.value, year.value);
console.log("中美科技实力对比", res);
if (res.code === 200 && res.data) {
tableData.value = res.data[0].children;
......@@ -392,6 +418,7 @@ const handlegetTechnologyGameAnalysis = async () => {
};
onMounted(async () => {
await handleGetChartDict();
await handleGetYearDict();
await handleGetCompare();
await handlegetTechnologyGameAnalysis();
// const dom = document.getElementById("char");
......@@ -566,6 +593,7 @@ const lineOption = ref({
},
yAxis: {
type: "value",
min: 77,
// name: "指数",
nameLocation: "top",
nameGap: 35,
......
......@@ -37,7 +37,7 @@
<fourSuppress></fourSuppress>
<!-- 中美博弈概况 -->
<commonTitle id="zm-overview" title="中美博弈概况" style="margin-top: 64px; margin-bottom: 36px"></commonTitle>
<gameProfile></gameProfile>
<gameProfile />
<div class="bottom-info">
<div class="info-item">
<div class="info-item-left">
......
......@@ -4,8 +4,13 @@
<div class="home-top-bg"></div>
<div class="home-main-header">
<div class="home-main-header-center">
<SearchContainer style="margin-bottom: 0; margin-top: 48px; height: fit-content" v-if="containerRef"
placeholder="搜索政令" :containerRef="containerRef" areaName="政令" />
<SearchContainer
style="margin-bottom: 0; margin-top: 48px; height: fit-content"
v-if="containerRef"
placeholder="搜索政令"
:containerRef="containerRef"
areaName="政令"
/>
</div>
<!-- <div class="home-main-header-footer" v-show="!isShow">
<div class="home-main-header-footer-item">
......@@ -31,23 +36,28 @@
</div> -->
<div class="date-box" v-if="govInsList.length">
<div class="date-icon">
<img :src="tipsTcon" alt="">
<img :src="tipsTcon" alt="" />
</div>
<div class="date-text">近期美国各联邦政府机构发布涉华政令数量汇总</div>
<TimeTabPane @time-click="handleGetDepartmentList" />
</div>
<div class="home-main-header-item-box" v-if="govInsList.length">
<div class="organization-item" v-for="(item, index) in govInsList.slice(0, 7)" :key="index" @click="handleToInstitution(item)">
<div
class="organization-item"
v-for="(item, index) in govInsList.slice(0, 7)"
:key="index"
@click="handleToInstitution(item)"
>
<div class="item-left">
<img :src="item.orgImage || DefaultIcon2" alt="" />
</div>
<div class="item-right one-line-ellipsis">{{ item.orgName }}</div>
<div class="item-total">{{ item.total }}</div>
<el-icon color="var(--color-primary-100)"><ArrowRightBold /></el-icon>
<div class="item-dot" v-if="item.totalRecent">+{{item.totalRecent}}</div>
<div class="item-dot" v-if="item.totalRecent">+{{ item.totalRecent }}</div>
</div>
<div class="organization-item">
<div class="item-more">查看全部机构 ({{govInsList.length+1}}家)</div>
<div class="item-more">查看全部机构 ({{ govInsList.length + 1 }}家)</div>
<el-icon color="var(--color-primary-100)"><ArrowRightBold /></el-icon>
</div>
</div>
......@@ -77,8 +87,14 @@
{{ "查看详情 >" }}
</div>
</div>
<el-carousel ref="carouselRef" height="395px" :autoplay="true" :interval="3000" arrow="never"
indicator-position="none">
<el-carousel
ref="carouselRef"
height="395px"
:autoplay="true"
:interval="3000"
arrow="never"
indicator-position="none"
>
<el-carousel-item v-for="(item, index) in box1DataList" :key="index">
<div class="box1-main">
<div class="box1-main-left">
......@@ -95,7 +111,11 @@
{{ item.name }}
</div>
<div class="box1-main-right-info">
<AreaTag v-for="(tag, index) in item.industryList" :key="index" :tagName="tag.industryName" />
<AreaTag
v-for="(tag, index) in item.industryList"
:key="index"
:tagName="tag.industryName"
/>
</div>
<div class="box1-main-right-center">
{{ item.describe }}
......@@ -157,16 +177,27 @@
<div class="text">{{ "查看更多" }}</div>
</div>
</div> -->
<RiskSignal :list="warningList" @item-click="handleClickToDetail" @more-click="handleToMoreRiskSignal"
riskLevel="signalLevel" postDate="signalTime" name="signalTitle">
<RiskSignal
:list="warningList"
@item-click="handleClickToDetail"
@more-click="handleToMoreRiskSignal"
riskLevel="signalLevel"
postDate="signalTime"
name="signalTitle"
>
</RiskSignal>
</div>
<DivideHeader id="position2" class="divide2" :titleText="'资讯要闻'"></DivideHeader>
<div class="center-center">
<NewsList :newsList="newsList" @item-click="handleToNewsAnalysis" @more-click="handleToMoreNews" />
<!-- <NewsList :newsList="newsList" /> -->
<MessageBubble :messageList="messageList" @person-click="handleClickPerson" @info-click="handleGetMessage"
imageUrl="img" @more-click="handleToSocialDetail" />
<MessageBubble
:messageList="messageList"
@person-click="handleClickPerson"
@info-click="handleGetMessage"
imageUrl="img"
@more-click="handleToSocialDetail"
/>
</div>
<DivideHeader id="position3" class="divide3" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer">
......@@ -176,21 +207,46 @@
<img src="./assets/images/box3-header-icon.png" alt="" />
</div>
<div class="box5-header-title">{{ "数量变化趋势" }}</div>
<div style="margin-right: 20px;">
<el-select @change="handleBox5" v-model="box5Params.proposeName" :empty-values="[null, undefined]" style="width:150px">
<div style="margin-right: 20px">
<el-select
@change="handleBox5"
v-model="box5Params.proposeName"
:empty-values="[null, undefined]"
style="width: 150px"
>
<el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
<el-option
v-for="item in keyOrganizationList"
:key="item.orgId"
:label="item.orgName"
:value="item.orgId"
/>
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleBox5" v-model="box5Params.domainId" :empty-values="[null, undefined]" style="width:120px">
<div style="margin-right: 20px">
<el-select
@change="handleBox5"
v-model="box5Params.domainId"
:empty-values="[null, undefined]"
style="width: 120px"
>
<el-option label="全部领域" value="" />
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleBox5" v-model="box5Params.year" placeholder="选择时间" style="width:120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
<div style="margin-right: 20px">
<el-select
@change="handleBox5"
v-model="box5Params.year"
placeholder="选择时间"
style="width: 120px"
>
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
......@@ -199,7 +255,7 @@
</div>
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsTcon" alt="">
<img :src="tipsTcon" alt="" />
</div>
<div class="data-origin-text">科技政令数量变化趋势,数据来源:美国各行政机构官网</div>
</div>
......@@ -215,15 +271,35 @@
<img src="./assets/images/box4-header-icon.png" alt="" />
</div>
<div class="box5-header-title">{{ "领域分布情况" }}</div>
<div style="margin-right: 20px;">
<el-select @change="handleBox6YearChange" v-model="box6Params.proposeName" :empty-values="[null, undefined]" style="width:150px">
<div style="margin-right: 20px">
<el-select
@change="handleBox6YearChange"
v-model="box6Params.proposeName"
:empty-values="[null, undefined]"
style="width: 150px"
>
<el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
<el-option
v-for="item in keyOrganizationList"
:key="item.orgId"
:label="item.orgName"
:value="item.orgId"
/>
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleBox6YearChange" v-model="box6Params.year" placeholder="选择时间" style="width: 120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
<div style="margin-right: 20px">
<el-select
@change="handleBox6YearChange"
v-model="box6Params.year"
placeholder="选择时间"
style="width: 120px"
>
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
......@@ -232,9 +308,9 @@
</div>
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsTcon" alt="">
<img :src="tipsTcon" alt="" />
</div>
<div class="data-origin-text">科技政领域分布情况,数据来源:美国各行政机构官网</div>
<div class="data-origin-text">科技政领域分布情况,数据来源:美国各行政机构官网</div>
</div>
<div class="ai-pane">
<AiButton />
......@@ -249,27 +325,57 @@
<img src="./assets/images/box5-header-icon.png" alt="" />
</div>
<div class="header-title">{{ "关键科技政令" }}</div>
<div style="margin-right: 20px;">
<el-select @change="handleGetKeyDecree" v-model="box7Params.proposeName" :empty-values="[null, undefined]" style="width:150px">
<div style="margin-right: 20px">
<el-select
@change="handleGetKeyDecree"
v-model="box7Params.proposeName"
:empty-values="[null, undefined]"
style="width: 150px"
>
<el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
<el-option
v-for="item in keyOrganizationList"
:key="item.orgId"
:label="item.orgName"
:value="item.orgId"
/>
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleGetKeyDecree" v-model="box7Params.domainId" :empty-values="[null, undefined]" style="width:120px">
<div style="margin-right: 20px">
<el-select
@change="handleGetKeyDecree"
v-model="box7Params.domainId"
:empty-values="[null, undefined]"
style="width: 120px"
>
<el-option label="全部领域" value="" />
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleGetKeyDecree" v-model="box7Params.year" placeholder="选择时间" style="width:120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
<div style="margin-right: 20px">
<el-select
@change="handleGetKeyDecree"
v-model="box7Params.year"
placeholder="选择时间"
style="width: 120px"
>
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<div class="box7-main">
<div class="box7-list">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index" @click="handleKeyDecree(item)">
<div
class="box7-item"
v-for="(item, index) in keyDecreeList"
:key="index"
@click="handleKeyDecree(item)"
>
<div class="icon">
<img src="./assets/images/warning.png" alt="" />
</div>
......@@ -283,12 +389,17 @@
</div>
</div>
</div>
<SimplePagination v-model:current-page="keyDecreeInfo.page" :page-size="keyDecreeInfo.size" :total="keyDecreeInfo.total" @page-change="handleGetKeyDecree" />
<SimplePagination
v-model:current-page="keyDecreeInfo.page"
:page-size="keyDecreeInfo.size"
:total="keyDecreeInfo.total"
@page-change="handleGetKeyDecree"
/>
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsTcon" alt="">
<img :src="tipsTcon" alt="" />
</div>
<div class="data-origin-text">关键科技政列表,数据来源:美国各行政机构官网</div>
<div class="data-origin-text">关键科技政列表,数据来源:美国各行政机构官网</div>
</div>
</div>
<div class="box8">
......@@ -297,21 +408,46 @@
<img src="./assets/images/box5-header-icon.png" alt="" />
</div>
<div class="header-title">{{ "关键条款词云" }}</div>
<div style="margin-right: 20px;">
<el-select @change="handleGetDecreeKeyInstruction" v-model="box8Params.proposeName" :empty-values="[null, undefined]" style="width:150px">
<div style="margin-right: 20px">
<el-select
@change="handleGetDecreeKeyInstruction"
v-model="box8Params.proposeName"
:empty-values="[null, undefined]"
style="width: 150px"
>
<el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
<el-option
v-for="item in keyOrganizationList"
:key="item.orgId"
:label="item.orgName"
:value="item.orgId"
/>
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleGetDecreeKeyInstruction" v-model="box8Params.domainId" :empty-values="[null, undefined]" style="width:120px">
<div style="margin-right: 20px">
<el-select
@change="handleGetDecreeKeyInstruction"
v-model="box8Params.domainId"
:empty-values="[null, undefined]"
style="width: 120px"
>
<el-option label="全部领域" value="" />
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</div>
<div style="margin-right: 20px;">
<el-select @change="handleGetDecreeKeyInstruction" v-model="box8Params.year" placeholder="选择时间" style="width:120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
<div style="margin-right: 20px">
<el-select
@change="handleGetDecreeKeyInstruction"
v-model="box8Params.year"
placeholder="选择时间"
style="width: 120px"
>
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
......@@ -320,9 +456,9 @@
</div>
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsTcon" alt="">
<img :src="tipsTcon" alt="" />
</div>
<div class="data-origin-text">科技政重点条款词云,数据来源:美国各行政机构官网</div>
<div class="data-origin-text">科技政重点条款词云,数据来源:美国各行政机构官网</div>
</div>
</div>
</div>
......@@ -336,10 +472,10 @@
<el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
</el-select>
</div>
<div style="flex: auto;"></div>
<div style="flex: auto"></div>
<el-checkbox v-model="isChina">只看涉华政令</el-checkbox>
<div class="select-box">
<el-select v-model="isSort" placeholder="发布时间" style="width:120px; margin-left:8px;">
<el-select v-model="isSort" placeholder="发布时间" style="width: 120px; margin-left: 8px">
<template #prefix>
<div class="icon1">
<img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" />
......@@ -360,9 +496,15 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="type in decreeTypeList" :key="type.id" v-model="checkedDecreeType" :label="type.typeId"
style="width: 180px" class="filter-checkbox"
@change="handleChangeCheckedDecreeType">
<el-checkbox
v-for="type in decreeTypeList"
:key="type.id"
v-model="checkedDecreeType"
:label="type.typeId"
style="width: 180px"
class="filter-checkbox"
@change="handleChangeCheckedDecreeType"
>
{{ type.typeName }}
</el-checkbox>
</div>
......@@ -375,12 +517,24 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-model="activeAreaList" label="all"
style="width: 100px" class="filter-checkbox" @change="checked => handleAreaChange('all', checked)">
<el-checkbox
v-model="activeAreaList"
label="all"
style="width: 100px"
class="filter-checkbox"
@change="checked => handleAreaChange('all', checked)"
>
{{ "全部领域" }}
</el-checkbox>
<el-checkbox v-for="area in areaList" :key="area.id" v-model="activeAreaList" :label="area.id"
style="width: 100px" class="filter-checkbox" @change="checked => handleAreaChange(area.id, checked)">
<el-checkbox
v-for="area in areaList"
:key="area.id"
v-model="activeAreaList"
:label="area.id"
style="width: 100px"
class="filter-checkbox"
@change="checked => handleAreaChange(area.id, checked)"
>
{{ area.name }}
</el-checkbox>
</div>
......@@ -393,8 +547,15 @@
</div>
<div class="select-main">
<div class="checkbox-group">
<el-checkbox v-for="time in pubTime" :key="time.id" v-model="activePubTime" :label="time.id"
style="width: 100px" class="filter-checkbox" @change="checked => handlePubTimeChange(time.id, checked)">
<el-checkbox
v-for="time in pubTime"
:key="time.id"
v-model="activePubTime"
:label="time.id"
style="width: 100px"
class="filter-checkbox"
@change="checked => handlePubTimeChange(time.id, checked)"
>
{{ time.name }}
</el-checkbox>
</div>
......@@ -409,7 +570,12 @@
<div class="title">{{ "政令库" }}</div>
</div>
<div class="content-box" v-show="decreeList">
<div class="main-item" v-for="(item, index) in decreeList" :key="index" @click="handleClickDecree(item)">
<div
class="main-item"
v-for="(item, index) in decreeList"
:key="index"
@click="handleClickDecree(item)"
>
<div class="main-item-left">
<div class="left-left">
{{ item.time?.split("-")[0] }}<br />{{ item.time?.split("-")[1] }}月{{
......@@ -440,8 +606,14 @@
{{ `共 ${totalDecreesNum} 项` }}
</div>
<div class="footer-right">
<el-pagination @current-change="handleCurrentChange" :pageSize="10" :current-page="currentPage"
background layout="prev, pager, next" :total="totalDecreesNum" />
<el-pagination
@current-change="handleCurrentChange"
:pageSize="10"
:current-page="currentPage"
background
layout="prev, pager, next"
:total="totalDecreesNum"
/>
</div>
</div>
</div>
......@@ -454,11 +626,11 @@
<script setup>
import { onMounted, ref, watch, nextTick, reactive } from "vue";
import router from "@/router";
import WordCloudChart from "@/components/base/WordCloundChart/index.vue"
import WordCloudChart from "@/components/base/WordCloundChart/index.vue";
import SimplePagination from "@/components/SimplePagination.vue";
import TimeTabPane from '@/components/base/TimeTabPane/index.vue';
import AiButton from '@/components/base/Ai/AiButton/index.vue';
import AiPane from '@/components/base/Ai/AiPane/index.vue';
import TimeTabPane from "@/components/base/TimeTabPane/index.vue";
import AiButton from "@/components/base/Ai/AiButton/index.vue";
import AiPane from "@/components/base/Ai/AiPane/index.vue";
import {
getDepartmentList,
getLatestDecree,
......@@ -470,7 +642,7 @@ import {
getDecreeOrderList,
getDecreehylyList,
getDecreeTypeList,
getKeyOrganization,
getKeyOrganization
} from "@/api/decree/home";
import { getPersonSummaryInfo } from "@/api/common/index";
import { getNews, getSocialMedia } from "@/api/general/index";
......@@ -492,21 +664,21 @@ const pageSize = ref(10);
// 处理页码改变事件
const handleCurrentChange = page => {
currentPage.value = page;
handleToPosi('position4')
handleToPosi("position4");
handleGetDecreeOrderList();
};
// 机构列表
const govInsList = ref([]);
const checkedGovIns = ref([]);
const handleGetDepartmentList = async (event) => {
let day = 7
if (event?.time === '近一周') day = 7
if (event?.time === '近一月') day = 30
if (event?.time === '近一年') day = 365
const handleGetDepartmentList = async event => {
let day = 7;
if (event?.time === "近一周") day = 7;
if (event?.time === "近一月") day = 30;
if (event?.time === "近一年") day = 365;
try {
const res = await getDepartmentList({day});
const res = await getDepartmentList({ day });
console.log("机构列表", res);
if (res.code === 200 && res.data) {
govInsList.value = res.data;
......@@ -654,7 +826,7 @@ const newsList = ref([
]);
const handleGetNews = async () => {
try {
const res = await getNews({moduleId: "0101"});
const res = await getNews({ moduleId: "0101" });
console.log("新闻资讯", res);
if (res.code === 200 && res.data) {
// newsList.value = res.data || []
......@@ -717,7 +889,7 @@ const handleGetMessage = async () => {
remarksId: item.remarksId
};
});
} catch (error) { }
} catch (error) {}
};
handleGetMessage();
......@@ -775,7 +947,7 @@ const handleClickPerson = async item => {
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} catch (error) { }
} catch (error) {}
};
// 获取最近年份列表
......@@ -797,10 +969,10 @@ const chart1Data = ref({
});
const box5Params = reactive({
year: yearList[0].value,
domainId: '',
proposeName: '',
})
const summarize1 = ref()
domainId: "",
proposeName: ""
});
const summarize1 = ref();
const handleGetDecreeYearOrder = async () => {
try {
let { year, domainId, proposeName } = box5Params;
......@@ -817,52 +989,52 @@ const handleGetDecreeYearOrder = async () => {
chart1Data.value.dataY = res.data.map(item => {
return item.count;
});
summarize1.value = await onChartInterpretation({type:"柱状图",name:"数量变化趋势",data:res.data})
summarize1.value = await onChartInterpretation({ type: "柱状图", name: "数量变化趋势", data: res.data });
}
} catch (error) {
console.error("行政令发布频度error", error);
}
};
// AI智能总结
const onChartInterpretation = async (text) => {
const response = await fetch('/aiAnalysis/chart_interpretation', {
method: 'POST',
const onChartInterpretation = async text => {
const response = await fetch("/aiAnalysis/chart_interpretation", {
method: "POST",
headers: {
"X-API-Key": "aircasKEY19491001",
'Content-Type': 'application/json',
"Content-Type": "application/json"
},
body: JSON.stringify({text}) // 把参数转为JSON字符串
body: JSON.stringify({ text }) // 把参数转为JSON字符串
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let summarize = '';
let buffer = "";
let summarize = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (line.startsWith('data: ')) {
if (line.startsWith("data: ")) {
const content = line.substring(6);
const textMatch = content.match(/"解读":\s*"([^"]*)"/);
if (textMatch && textMatch[1]) summarize = textMatch[1];
}
}
}
return summarize
}
return summarize;
};
const handleBox5 = async () => {
await handleGetDecreeYearOrder();
let chart1 = getBarChart(chart1Data.value.dataX, chart1Data.value.dataY);
chart1.yAxis.name = "数量";
chart1.yAxis.nameTextStyle = { align: 'right' }
chart1.yAxis.nameTextStyle = { align: "right" };
setChart(chart1, "chart1");
};
......@@ -881,9 +1053,9 @@ const chart2Data = ref([
const box6Params = reactive({
year: yearList[0].value,
proposeName: '',
proposeName: ""
});
const summarize2 = ref()
const summarize2 = ref();
const handleGetDecreeArea = async () => {
try {
let { year, proposeName } = box6Params;
......@@ -899,7 +1071,7 @@ const handleGetDecreeArea = async () => {
value: item.count
};
});
summarize2.value = await onChartInterpretation({type:"环形图",name:"领域分布情况",data:res.data})
summarize2.value = await onChartInterpretation({ type: "环形图", name: "领域分布情况", data: res.data });
}
} catch (error) {
console.error("政令科技领域error", error);
......@@ -920,19 +1092,19 @@ const keyDecreeList = ref([]);
const keyDecreeInfo = reactive({
total: 0,
page: 1,
size: 4,
})
size: 4
});
const box7Params = reactive({
year: yearList[0].value,
domainId: '',
proposeName: '',
})
domainId: "",
proposeName: ""
});
const handleGetKeyDecree = async () => {
try {
let { year, domainId, proposeName } = box7Params;
const res = await getKeyDecree({
pageSize:keyDecreeInfo.size,
pageNum:keyDecreeInfo.page-1,
pageSize: keyDecreeInfo.size,
pageNum: keyDecreeInfo.page - 1,
year,
domainId: domainId || undefined,
orgId: proposeName || undefined
......@@ -949,16 +1121,16 @@ const handleGetKeyDecree = async () => {
};
});
}
} catch (error) { }
} catch (error) {}
};
// 政令重点条款
const wordCloudData = ref([]);
const box8Params = reactive({
year: yearList[0].value,
domainId: '',
proposeName: '',
})
domainId: "",
proposeName: ""
});
const handleGetDecreeKeyInstruction = async () => {
try {
let { year, domainId, proposeName } = box8Params;
......@@ -968,7 +1140,7 @@ const handleGetDecreeKeyInstruction = async () => {
orgId: proposeName || undefined
});
console.log("政令重点条款", res);
wordCloudData.value = res.data.map(item => ({name: item.clause, value: item.count}));
wordCloudData.value = res.data.map(item => ({ name: item.clause, value: item.count }));
} catch (error) {
console.error("政令重点条款error", error);
}
......@@ -1013,7 +1185,7 @@ const handleGetDecreeTypeList = async () => {
if (res.code === 200 && res.data) {
decreeTypeList.value = res.data;
}
} catch (error) { }
} catch (error) {}
};
// 查看社交媒体详情
const handleToSocialDetail = item => {
......@@ -1097,7 +1269,7 @@ const handleGetAreaList = async () => {
// 获取列表后重新查询
handleGetDecreeOrderList();
}
} catch (error) { }
} catch (error) {}
};
const totalDecreesNum = ref(0);
......@@ -1202,10 +1374,10 @@ const onKeyOrganization = async () => {
const res = await getKeyOrganization();
console.log("关键机构", res);
if (res.code === 200) {
keyOrganizationList.value = res.data.map(item => ({ orgName:item.orgName, orgId:item.id }));
keyOrganizationList.value = res.data.map(item => ({ orgName: item.orgName, orgId: item.id }));
}
} catch (error) { }
}
} catch (error) {}
};
onMounted(async () => {
onKeyOrganization();
......@@ -1261,7 +1433,7 @@ onMounted(async () => {
height: 16px;
font-size: 0px;
margin-right: 8px;
img{
img {
width: 100%;
height: 100%;
}
......@@ -1286,7 +1458,9 @@ onMounted(async () => {
overflow-y: auto;
.home-top-bg {
background: url("./assets/images/background.png"), linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background:
url("./assets/images/background.png"),
linear-gradient(180deg, rgba(229, 241, 254, 1) 0%, rgba(246, 251, 255, 0) 30%);
background-size: 100% 100%;
position: absolute;
width: 100%;
......@@ -1442,7 +1616,9 @@ onMounted(async () => {
align-items: center;
justify-content: center;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
transition:
transform 0.3s ease,
box-shadow 0.3s ease;
position: relative;
&:hover {
......@@ -1494,7 +1670,7 @@ onMounted(async () => {
top: -10px;
padding: 0 8px;
height: 26px;
background-color: #FF4D4F;
background-color: #ff4d4f;
color: white;
font-size: 16px;
line-height: 26px;
......
......@@ -368,19 +368,29 @@
</el-col>
</el-row>
<el-row :gutter="20" style="width: 1600px; margin: 0 auto; height: 505px; margin-top: 16px">
<el-row :gutter="20" style="width: 1600px; margin: 0 auto; height: 540px; margin-top: 16px">
<el-col :span="8">
<custom-container title="实体领域分布" :titleIcon="radarIcon" height="480px">
<custom-container title="实体领域分布" :titleIcon="radarIcon" height="520px">
<template #header-right>
<el-checkbox v-model="domainChecked" label="50%规则" size="large" />
</template>
<template #default>
<EChart :option="radarOption" autoresize :style="{ height: '460px' }" />
<EChart :option="radarOption" autoresize :style="{ height: '400px' }" />
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">出口管制实体领域分布情况,数据来源:美国各行政机构官网</div>
</div>
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="radarChart.interpretation" />
</div>
</template>
</custom-container>
</el-col>
<el-col :span="16">
<custom-container title="实体清单数量增长趋势" :titleIcon="qushiIcon" height="480px">
<custom-container title="实体清单数量增长趋势" :titleIcon="qushiIcon" height="520px">
<template #header-right>
<div style="display: flex; align-items: center; gap: 16px">
<el-checkbox v-model="trendChecked" label="50%规则" size="large" />
......@@ -391,6 +401,16 @@
</template>
<template #default>
<EChart :option="trendOption" autoresize :style="{ height: '400px' }" />
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsIcon" alt="" />
</div>
<div class="data-origin-text">出口管制实体清单数量增长趋势,数据来源:美国各行政机构官网</div>
</div>
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="trendChart.interpretation" />
</div>
</template>
</custom-container>
</el-col>
......@@ -703,7 +723,7 @@
<script setup>
//这是一个备注
import NewsList from "@/components/base/newsList/index.vue";
import RiskSignal from "@/components/base/RiskSignal/index.vue";
import RiskSignal from "@/components/base/riskSignal/index.vue";
import { onMounted, ref, computed, reactive, shallowRef, watch, nextTick } from "vue";
import { useContainerScroll } from "@/hooks/useScrollShow";
const homeMainRef = ref(null);
......@@ -712,9 +732,10 @@ import * as echarts from "echarts";
import setChart from "@/utils/setChart";
import { ElMessage, ElMessageBox } from "element-plus";
import { DArrowRight, Warning, Search } from "@element-plus/icons-vue";
import { DArrowRight, Warning, Search, TrendCharts } from "@element-plus/icons-vue";
import EChart from "@/components/Chart/index.vue";
import { TAGTYPE } from "@/public/constant";
import { useChartInterpretation } from "@/views/exportControl/utils/common";
import { useGotoCompanyPages } from "@/router/modules/company";
import { useGotoNewsDetail } from "@/router/modules/news";
const gotoCompanyPages = useGotoCompanyPages();
......@@ -726,6 +747,8 @@ const router = useRouter();
import CustomContainer from "@/components/Container/index.vue";
import ClickableCard from "./components/link.vue";
import AiButton from "@/components/base/Ai/AiButton/index.vue";
import AiPane from "@/components/base/Ai/AiPane/index.vue";
import InfoCard from "./components/info.vue";
import CustomTitle from "./components/title.vue";
import CommonPrompt from "./commonPrompt/index.vue";
......@@ -746,6 +769,7 @@ import entityIcon from "./assets/images/icon-entity.png";
import comTitle from "./assets/images/panel1_1.png";
import getMultiLineChart from "./utils/multiLineChart";
import icon01 from "./assets/images/jianzhu.png";
import tipsIcon from "./assets/icons/info-icon.png";
import {
getEntitiesDataCount,
getEntitiesDataInfo,
......@@ -1015,6 +1039,7 @@ const handleToSocialDetail = item => {
});
window.open(route.href, "_blank");
};
const trendChart = useChartInterpretation();
// 获取趋势图数据
const fetchTrendData = async () => {
try {
......@@ -1026,6 +1051,7 @@ const fetchTrendData = async () => {
});
if (res && res[0] && res[0].yearDomainCount) {
trendOption.value = processYearDomainCountData(res[0].yearDomainCount);
trendChart.interpret({ type: "柱状图", name: "实体清单数量增长趋势", data: res[0].yearDomainCount });
}
} catch (error) {
console.error("获取趋势图数据失败:", error);
......@@ -1205,7 +1231,7 @@ const radarOption = ref({
},
radar: {
radius: "60%",
center: ["50%", "50%"],
center: ["52%", "45%"],
// shape: 'circle',
indicator: [],
axisName: {
......@@ -1225,11 +1251,14 @@ const radarOption = ref({
]
});
const radarChart = useChartInterpretation();
// 获取雷达图数据
const fetchRadarData = async checked => {
try {
const data = await getSanDomainCount(checked, "export");
console.log("雷达数据data", data);
if (data && Array.isArray(data) && data.length > 0) {
radarChart.interpret({ type: "雷达图", name: "实体领域分布", data: data });
// 收集所有可能的领域名称
const allDomains = new Set();
data.forEach(item => {
......@@ -3597,4 +3626,50 @@ const handleMediaClick = item => {
background: rgba(255, 255, 255, 1);
}
}
.data-origin-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 22px 0;
.data-origin-icon {
width: 16px;
height: 16px;
font-size: 0px;
margin-right: 8px;
img {
width: 100%;
height: 100%;
}
}
.data-origin-text {
font-family: Source Han Sans CN;
font-size: 14px;
color: var(--text-primary-50-color);
}
}
.ai-pane {
position: absolute;
right: 0px;
bottom: 15px;
z-index: 2;
:deep(.ai-pane-wrapper) {
display: none;
}
:deep(.ai-button-wrapper) {
display: flex;
}
&:hover {
width: 100%;
bottom: 0px;
:deep(.ai-pane-wrapper) {
display: block;
}
:deep(.ai-button-wrapper) {
display: none;
}
}
}
</style>
import * as echarts from "echarts";
import chinaJson from "./China.json";
import _ from "lodash";
import { name } from "dayjs/locale/zh-cn";
//饼图
export function getPieOption(data, title) {
let option = {
......@@ -1022,6 +1023,12 @@ export const getMultipleBarChart_m = object => {
},
yAxis: {
type: "value",
name: "数量",
nameLocation: "end",
nameGap: 5,
nameTextStyle: {
padding: [0, 40, 10, 0] // [上, 右, 下, 左] —— 减少右侧 padding 相当于左移
},
splitNumber: 5,
alignTicks: false,
axisLabel: {
......
import { ref } from "vue";
export const useChartInterpretation = () => {
const loading = ref(false);
const interpretation = ref("");
const error = ref(null);
const interpret = async text => {
loading.value = true;
error.value = null;
interpretation.value = "";
try {
const response = await fetch("/aiAnalysis/chart_interpretation", {
method: "POST",
headers: {
"X-API-Key": "aircasKEY19491001",
"Content-Type": "application/json"
},
body: JSON.stringify({ text })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
buffer = lines.pop() || "";
for (const line of lines) {
if (line.startsWith("data: ")) {
const content = line.substring(6);
const textMatch = content.match(/"解读":\s*"([^"]*)"/);
if (textMatch && textMatch[1]) {
interpretation.value = textMatch[1];
}
}
}
}
} catch (err) {
error.value = err.message || "AI 解读失败";
console.error("AI Chart Interpretation Error:", err);
} finally {
loading.value = false;
}
};
return {
loading,
interpretation,
error,
interpret
};
};
......@@ -19,11 +19,7 @@
<div class="title">
<div class="box"></div>
<div class="text">科技领域</div>
<el-checkbox
v-model="allTechFieldsChecked"
label="全部"
@change="handleFilterChange(item, techFields, 'techFields')"
/>
<!-- <el-checkbox v-model="allTechFieldsChecked" label="全部" @change="handleAllTechFieldsChange" /> -->
</div>
<div class="checkbox-group">
<el-checkbox
......@@ -36,12 +32,8 @@
</div>
<div class="title">
<div class="box"></div>
<div class="text">管控原因</div>
<el-checkbox
v-model="allReasonChecked"
label="全部"
@change="handleFilterChange(item, controlReason, 'reason')"
/>
<div class="text">管控等级</div>
<!-- <el-checkbox v-model="allControlReasonChecked" label="全部" @change="handleAllControlReasonChange" /> -->
</div>
<div class="checkbox-group">
<el-checkbox
......@@ -70,7 +62,7 @@
<div class="list-content" v-for="(ele, j) in element.cclChildren" :key="j">
<div class="content-title" @click="ele.isExpand = !ele.isExpand">
<div class="code-zone">
<!-- <div class="dot" v-if="ele.isDot"></div> -->
<div class="dot" v-if="ele.changeFlag"></div>
<span class="code">{{ ele.cclCode }}</span>
</div>
<span class="name">{{ ele.cclTitleZh }}</span>
......@@ -131,9 +123,9 @@ const getTechFields = async () => {
const res = await getAreaType();
if (res && res.code === 200) {
console.log("-----getTechFields", res.data);
techFields.value = res.data;
techFields.value = [{ id: "0", name: "全部领域", checked: true }].concat(res.data);
// 默认选中第一个
techFields.value[0].checked = true;
// techFields.value[0].checked = true;
}
} catch (error) {
console.error("获取科技领域字典失败:", error);
......@@ -146,12 +138,37 @@ const getControlReasonList = async () => {
const res = await getControlReason();
if (res && res.code === 200) {
console.log("-----getControlReasonList", res.data);
controlReason.value = res.data;
controlReason.value = [{ id: "0", name: "全部等级", checked: true }].concat(res.data);
// 默认选中第一个
controlReason.value[0].checked = true;
// controlReason.value[0].checked = true;
}
} catch (error) {
consoler"cl c.v.filter(item => item.checked).map(item => +item.id);
console.error("获取管控原因字典失败:", error);
}
};
const searchKeyword = ref("");
const onlyChina = ref(false);
const viewNew = ref(true);
// 获取ccl清单列表
const getCclList = async () => {
let techDomains = [];
// 判断是否“全部领域”被选中(即 techFields[0].checked === true)
if (techFields.value.length > 0 && techFields.value[0].checked) {
techDomains = []; // 全部领域 → 不传过滤条件(空数组)
} else {
// 否则,只取非 "0" 且 checked 的项的 id
techDomains = techFields.value.filter(item => item.id !== "0" && item.checked).map(item => item.id);
}
let controls = [];
if (controlReason.value.length > 0 && controlReason.value[0].checked) {
controls = []; // 全部等级 → 不过滤
} else {
controls = controlReason.value.filter(item => item.id !== "0" && item.checked).map(item => item.id);
}
// let controls = controlReason.value.filter(item => item.checked).map(item => item.id);
const params = {
categoryCode: currentCCLType.value,
techDomainIds: techDomains,
......@@ -164,70 +181,7 @@ const getControlReasonList = async () => {
try {
// const res = await getCclQuery(null);
const res = await getCclQuery(params);
// const res = {
// "code": 200,
// "message": "操作成功",
// "success": true,
// "data": [
// {
// "id": 1,
// "cclCode": "0",
// "cclTitle": "Nuclear Materials, Facilities and Equipment and Miscellaneous",
// "cclTitleZh": "核材料、设备设施及其他类似物项",
// "cclDescription": null,
// "cclDescriptionZh": null,
// "cclChildren": [
// {
// "id": 11,
// "cclCode": "A",
// "cclTitle": "Equipment, Assemblies and Components",
// "cclTitleZh": "设备、组件和部件",
// "cclDescription": null,
// "cclDescriptionZh": null,
// "cclChildren": [
// {
// "id": 1,
// "cclCode": "0A002",
// "cclTitle": "Power generating or propulsion equipment \"specially designed\" for use with space, marine or mobile \"nuclear reactors\". (These items are \"subject to the ITAR.\" See 22 CFR parts 120 through 130.)",
// "cclTitleZh": "专为太空、海洋或移动“核反应堆”设计的发电或推进设备。(这些项目“受 ITAR 约束”。参见 22 CFR 第 120 至 130 部分。)",
// "cclDescription": null,
// "cclDescriptionZh": null,
// "cclChildren": null
// },
// {
// "id": 2,
// "cclCode": "0A501",
// "cclTitle": "Firearms (except 0A502 shotguns, 0A506 semi-automatic rifles, 0A507 semi-automatic pistols, and 0A508 semi-automatic shotguns) and related commodities (except semi-automatic related commodities enumerated or otherwise described in Eccn 0A509 for Eccns 0A506, 0A507, or 0A508) as follows (see List of Items controlled).",
// "cclTitleZh": "火器(除 0A502 霰弹枪、0A506 半自动步枪、0A507 半自动手枪和 0A508 半自动霰弹枪外)及相关商品(除 Eccn 0A509 中列举或以其他方式描述的 Eccns 0A506、0A507 或 0A508 相关物品外),具体如下(参见管制物品列表)。",
// "cclDescription": "<p class=\"flush-paragraph-1\"> <span class=\"minor-caps\">License Requirements</span></p><p class=\"flush-paragraph-1\"><em>Reason for Control:</em> NS, RS, FC, UN, AT</p><div class=\"table-wrapper\"><div class=\"gpotbl_div\"><table border=\"1\" cellpadding=\"1\" cellspacing=\"1\" class=\"gpo_table\" frame=\"void\" width=\"100%\"><thead><tr><th class=\"center\">Control(s)</th><th class=\"center\">Country chart<br>(see Supp. No. 1 to part 738)</th></tr></thead><tbody><tr><td class=\"left\">NS applies to entire entry except 0A501.y</td><td class=\"left\">NS Column 1.</td></tr><tr><td class=\"left\">RS applies to entire entry except 0A501.y</td><td class=\"left\">RS Column 1.</td></tr><tr><td class=\"left\">FC applies to entire entry except 0A501.y</td><td class=\"left\">FC Column 1.</td></tr><tr><td class=\"left\">UN applies to entire entry</td><td class=\"left\">See § 746.1 of the EAR for UN controls.</td></tr><tr><td class=\"left\">AT applies to entire entry</td><td class=\"left\">AT Column 1.</td></tr></tbody></table></div></div><div class=\"note\"><div class=\"header\"><em>License Requirement Note:</em></div><p><em>In addition to using the Commerce Country Chart to determine license requirements, a license is required for exports and reexports of ECCN 0A501.y.7 firearms to the People's Republic of China.</em></p></div><p class=\"flush-paragraph-1\">List Based License Exceptions (See Part 740 for a Description of All License Exceptions)</p><p class=\"flush-paragraph-1\"><em>LVS:</em> $500 for 0A501.c, .d, and .x.</p><p class=\"flush-paragraph-1\">$500 for 0A501.c, .d, .e, and .x if the ultimate destination is Canada.</p><p class=\"flush-paragraph-1\"><em>GBS:</em> N/A</p><p class=\"flush-paragraph-1\"> <span class=\"minor-caps\">Special Conditions for STA</span></p><p class=\"flush-paragraph-1\">License Exception STA may not be used for ECCN 0A501.a, .b, .c, .d, or .e, to any of the destinations listed in Country Group A:5 or A:6 (See supplement no.1 to part 740 of the EAR). License Exception STA may not be used for any item in this entry to any of the destinations listed in Country Group A:6 (See Supplement No.1 to part 740 of the EAR).</p><p class=\"flush-paragraph-1\"> <span class=\"minor-caps\">List of Items Controlled</span></p><p class=\"flush-paragraph-1\"><em>Related Controls:</em> (1) See USML Category I for firearms that are fully automatic, and certain related parts, components, accessories, and attachments (including magazines with a capacity of greater than 50 rounds). (2) See ECCN 0A506 for semi-automatic rifles. (3) See ECCN 0A507 for semi-automatic pistols. (4) See ECCN 0A508 for semi-automatic shotguns and ECCN 0A502 for certain \"parts\" and \"components\" for semi-automatic shotguns that are not controlled by 0A509.a or .c. (5) See ECCN 0A509 for enumerated or otherwise described \"parts,\" \"components,\" devices, \"accessories,\" and \"attachments\" for ECCNs 0A506, 0A507, and 0A508. (6) See .d, .x, and .y of this entry for other \"parts,\" \"components,\" \"accessories,\" and \"attachments\" \"specially designed\" for 0A506 and 0A507, or 0A508. (7) See ECCN 0A502 for non-automatic shotguns and their \"parts\" and \"components\" that are subject to the EAR and for certain \"parts\" and \"components\" for semi-automatic shotguns that are not controlled by 0A509.a or .c. (8) See ECCN 0A504 and USML Category XII for controls on optical sighting devices.</p><p class=\"flush-paragraph-1\"><em>Related Definitions:</em> N/A.</p><p class=\"flush-paragraph\"><em>Items:</em></p><p>a. Non-automatic and non-semi-automatic firearms equal to .50 caliber (12.7 mm) or less.</p><div class=\"note\"><div class=\"header\"><em>Note 1 to paragraph 0A501.a:</em></div><p><em>'Combination pistols' are controlled under ECCN 0A501.a. A 'combination pistol' (a.k.a., a combination gun) has at least one rifled barrel and at least one smoothbore barrel (generally a shotgun style barrel).</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 2 to paragraph 0A501.a:</em></div><p><em>Semi-automatic firearms</em> equal to .50 caliber (12.7 mm) or less <em>are controlled under ECCNs 0A506 and 0A507.</em></p></div><div class=\"note\"><div class=\"header\"><em>Technical Note to 0A501.a:</em></div><p><em>Firearms described in 0A501.a include those chambered for the .50 BMG cartridge.</em></p></div><p>b. Non-automatic and non-semi-automatic rifles, carbines, revolvers or pistols with a caliber greater than .50 inches (12.7 mm) but less than or equal to .72 inches (18.0 mm).</p><p>c. The following types of \"parts\" and \"components\" if \"specially designed\" for a commodity controlled by paragraph .a or .b of this entry or ECCNs 0A506 or 0A507, or USML Category I (unless otherwise enumerated or elsewhere specified on the USML or controlled under ECCN 0A509): Barrels, cylinders, barrel extensions, mounting blocks (trunnions), bolts, bolt carriers, operating rods, gas pistons, trigger housings, triggers, hammers/striker, sears, disconnectors, pistol grips that contain fire control \"parts\" or \"components\" (<em>e.g.,</em> triggers, hammers/striker, sears, disconnectors) and buttstocks that contain fire control \"parts\" or \"components.\"</p><div class=\"note\"><div class=\"header\"><em>Technical Note to 0A501.c:</em></div><p><em>Barrel blanks that have reached a stage in manufacturing in which they are either chambered or rifled are controlled by 0A501.c.</em></p></div><p>d. Detachable magazines with a capacity of 17 to 50 rounds \"specially designed\" for a commodity controlled by paragraph .a or .b of this entry or controlled by ECCNs 0A506 or 0A507.</p><div class=\"note\"><div class=\"header\"><em>Note 3 to paragraph 0A501.d</em></div><p><em>Magazines with a capacity of 16 rounds or less are controlled under 0A501.x; for magazines with a capacity greater than 50 rounds, see USML Category I. Magazines that hold only blank ammunition controlled under 0A505.d are controlled under 0A501.d or 0A501.x, depending on the magazine's capacity.</em></p></div><p>e. Receivers (frames) and \"complete breech mechanisms,\" including castings, forgings, stampings, or machined items thereof, \"specially designed\" for a commodity controlled by paragraph .a or .b of this entry.</p><div class=\"note\"><div class=\"header\"><em>Note 4 to 0A501.e:</em></div><p><em>Frames (receivers) under 0A501.e refers to any \"part\" or \"component\" of the firearm that has or is customarily marked with a serial number when required by law. This paragraph 0A501.e is synonymous with a \"part\" or \"component\" that is regulated by the Bureau of Alcohol, Tobacco, Firearms and Explosives (see <a href=\"https://www.govinfo.gov/link/uscode/18/921\" class=\"usc external\" target=\"_blank\" rel=\"noopener noreferrer\">18 U.S.C. 921(a)(3)</a>; <a href=\"https://www.ecfr.gov/current/title-27/part-447\" class=\"cfr external\">27 CFR parts 447</a>, <a href=\"https://www.ecfr.gov/current/title-27/part-478\" class=\"cfr external\">478</a>, and <a href=\"https://www.ecfr.gov/current/title-27/part-479\" class=\"cfr external\">479</a>,) as a firearm.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 5 to 0A501.e:</em></div><p><em>Frames (receivers) \"specially designed\" for semi-automatic firearms are controlled under ECCN 0A509.b or .c.</em></p></div><p>f. through w. [Reserved]</p><p>x. \"Parts\" and \"components\" that are \"specially designed\" for a commodity classified under paragraphs .a through .c of this entry, a commodity classified under ECCNs 0A506 or 0A507, or the USML and not elsewhere specified on the USML or CCL or controlled under ECCN 0A509.</p><p>y. Specific \"parts,\" \"components,\" \"accessories\" and \"attachments\" \"specially designed\" for a commodity subject to control in this ECCN, ECCNs 0A506, 0A507, or common to a defense article in USML Category I and not elsewhere specified in the USML or CCL as follows, and \"parts,\" \"components,\" \"accessories,\" and \"attachments\" \"specially designed\" therefor.</p><p>y.1. Stocks (including adjustable, collapsible, blades and braces), grips, handguards, or forends, that do not contain any fire control \"parts\" or \"components\" (<em>e.g.,</em> triggers, hammers/striker, sears, disconnectors);</p><p>y.2 through y.5. [Reserved]</p><p>y.6. Bayonets; and</p><p>y.7. Firearms manufactured from 1890 to 1898 and reproductions thereof.</p><div class=\"note\"><div class=\"header\"><em>Technical Note 1 to 0A501:</em></div><p><em>ECCN 0A501 includes \"parts\" and \"components\" that are not \"subject to the ITAR\" even though they are common to firearms described in ECCN 0A501 and to those firearms \"subject to the ITAR.\"</em></p></div><div class=\"note\"><div class=\"header\"><em>Technical Note 2 to 0A501:</em></div><p><em>A receiver with any other controlled \"part\" or \"component\" ( e.g., a barrel (0A501.c), or trigger guard (0A501.x), or stock (0A501.y.1)) is still controlled under 0A501.e.</em></p></div><div class=\"note\"><div class=\"header\"><em>Technical Note 3 to 0A501:</em></div><p><em>Blank firing adapters, which are attachments to semi-automatic and automatic firearms used in conjunction with blank cartridges for safety and functional reasons and used for firearm training purposes by police, military, sporting shooters, as well as in the movie industry, are designated as EAR99.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 6 to 0A501:</em></div><p><em>Antique firearms (i.e., those manufactured before 1890) and reproductions thereof, muzzle loading and black powder firearms except those designs based on centerfire weapons of a post 1937 design, BB guns, pellet rifles, paint ball, and all other air rifles are EAR99 commodities.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 7 to 0A501:</em></div><p><em>Muzzle loading and black powder firearms with a caliber less than 20 mm that were manufactured post 1937 that are used for hunting or sporting purposes that were not \"specially designed\" for military use and are not described on the USML nor controlled as shotguns under ECCN 0A502 are EAR99 commodities.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 8 to 0A501:</em></div><p><em>Scope mounts or accessory rails, iron sights, sling swivels, and butt plates or recoil pads that are subject to the EAR are designated as EAR99. These commodities have been determined to no longer warrant being \"specially designed\" for purposes of ECCN 0A501.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 9 to 0A501:</em></div><p><em>A kit, including a replacement or repair kit, of firearms \"parts\" or \"components\" customarily sold and exported together takes on the classification of the most restrictive \"part\" or \"component\" that is included in the kit. For example, a kit containing 0A501.y and .x \"parts,\" is controlled as a 0A501.x kit because the .x \"part\" is the most restrictive \"part\" included in the kit. A complete 0A501 firearm disassembled in a kit form is controlled as a firearm under 0A501.a, .b, or .y.7.</em></p></div>",
// "cclDescriptionZh": "<p class=\"flush-paragraph-1\"> <span class=\"minor-caps\">License Requirements</span></p><p class=\"flush-paragraph-1\"><em>Reason for Control:</em> NS, RS, FC, UN, AT</p><div class=\"table-wrapper\"><div class=\"gpotbl_div\"><table border=\"1\" cellpadding=\"1\" cellspacing=\"1\" class=\"gpo_table\" frame=\"void\" width=\"100%\"><thead><tr><th class=\"center\">控制原因</th><th class=\"center\">Country chart<br>(参见第738部分补充1号文)</th></tr></thead><tbody><tr><td class=\"left\">NS applies to entire entry except 0A501.y</td><td class=\"left\">NS Column 1.</td></tr><tr><td class=\"left\">RS applies to entire entry except 0A501.y</td><td class=\"left\">RS Column 1.</td></tr><tr><td class=\"left\">FC applies to entire entry except 0A501.y</td><td class=\"left\">FC Column 1.</td></tr><tr><td class=\"left\">UN applies to entire entry</td><td class=\"left\">See § 746.1 of the EAR for UN controls.</td></tr><tr><td class=\"left\">AT applies to entire entry</td><td class=\"left\">AT Column 1.</td></tr></tbody></table></div></div><div class=\"note\"><div class=\"header\"><em>License Requirement Note:</em></div><p><em>In addition to using the Commerce Country Chart to determine license requirements, a license is required for exports and reexports of ECCN 0A501.y.7 firearms to the People's Republic of China.</em></p></div><p class=\"flush-paragraph-1\">List Based License Exceptions (See Part 740 for a Description of All License Exceptions)</p><p class=\"flush-paragraph-1\"><em>LVS:</em> $500 for 0A501.c, .d, and .x.</p><p class=\"flush-paragraph-1\">$500 for 0A501.c, .d, .e, and .x if the ultimate destination is Canada.</p><p class=\"flush-paragraph-1\"><em>GBS:</em> N/A</p><p class=\"flush-paragraph-1\"> <span class=\"minor-caps\">Special Conditions for STA</span></p><p class=\"flush-paragraph-1\">License Exception STA may not be used for ECCN 0A501.a, .b, .c, .d, or .e, to any of the destinations listed in Country Group A:5 or A:6 (See supplement no.1 to part 740 of the EAR). License Exception STA may not be used for any item in this entry to any of the destinations listed in Country Group A:6 (See Supplement No.1 to part 740 of the EAR).</p><p class=\"flush-paragraph-1\"> <span class=\"minor-caps\">List of Items Controlled</span></p><p class=\"flush-paragraph-1\"><em>Related Controls:</em> (1) See USML Category I for firearms that are fully automatic, and certain related parts, components, accessories, and attachments (including magazines with a capacity of greater than 50 rounds). (2) See ECCN 0A506 for semi-automatic rifles. (3) See ECCN 0A507 for semi-automatic pistols. (4) See ECCN 0A508 for semi-automatic shotguns and ECCN 0A502 for certain \"parts\" and \"components\" for semi-automatic shotguns that are not controlled by 0A509.a or .c. (5) See ECCN 0A509 for enumerated or otherwise described \"parts,\" \"components,\" devices, \"accessories,\" and \"attachments\" for ECCNs 0A506, 0A507, and 0A508. (6) See .d, .x, and .y of this entry for other \"parts,\" \"components,\" \"accessories,\" and \"attachments\" \"specially designed\" for 0A506 and 0A507, or 0A508. (7) See ECCN 0A502 for non-automatic shotguns and their \"parts\" and \"components\" that are subject to the EAR and for certain \"parts\" and \"components\" for semi-automatic shotguns that are not controlled by 0A509.a or .c. (8) See ECCN 0A504 and USML Category XII for controls on optical sighting devices.</p><p class=\"flush-paragraph-1\"><em>Related Definitions:</em> N/A.</p><p class=\"flush-paragraph\"><em>Items:</em></p><p>a. Non-automatic and non-semi-automatic firearms equal to .50 caliber (12.7 mm) or less.</p><div class=\"note\"><div class=\"header\"><em>Note 1 to paragraph 0A501.a:</em></div><p><em>'Combination pistols' are controlled under ECCN 0A501.a. A 'combination pistol' (a.k.a., a combination gun) has at least one rifled barrel and at least one smoothbore barrel (generally a shotgun style barrel).</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 2 to paragraph 0A501.a:</em></div><p><em>Semi-automatic firearms</em> equal to .50 caliber (12.7 mm) or less <em>are controlled under ECCNs 0A506 and 0A507.</em></p></div><div class=\"note\"><div class=\"header\"><em>Technical Note to 0A501.a:</em></div><p><em>Firearms described in 0A501.a include those chambered for the .50 BMG cartridge.</em></p></div><p>b. Non-automatic and non-semi-automatic rifles, carbines, revolvers or pistols with a caliber greater than .50 inches (12.7 mm) but less than or equal to .72 inches (18.0 mm).</p><p>c. The following types of \"parts\" and \"components\" if \"specially designed\" for a commodity controlled by paragraph .a or .b of this entry or ECCNs 0A506 or 0A507, or USML Category I (unless otherwise enumerated or elsewhere specified on the USML or controlled under ECCN 0A509): Barrels, cylinders, barrel extensions, mounting blocks (trunnions), bolts, bolt carriers, operating rods, gas pistons, trigger housings, triggers, hammers/striker, sears, disconnectors, pistol grips that contain fire control \"parts\" or \"components\" (<em>e.g.,</em> triggers, hammers/striker, sears, disconnectors) and buttstocks that contain fire control \"parts\" or \"components.\"</p><div class=\"note\"><div class=\"header\"><em>Technical Note to 0A501.c:</em></div><p><em>Barrel blanks that have reached a stage in manufacturing in which they are either chambered or rifled are controlled by 0A501.c.</em></p></div><p>d. Detachable magazines with a capacity of 17 to 50 rounds \"specially designed\" for a commodity controlled by paragraph .a or .b of this entry or controlled by ECCNs 0A506 or 0A507.</p><div class=\"note\"><div class=\"header\"><em>Note 3 to paragraph 0A501.d</em></div><p><em>Magazines with a capacity of 16 rounds or less are controlled under 0A501.x; for magazines with a capacity greater than 50 rounds, see USML Category I. Magazines that hold only blank ammunition controlled under 0A505.d are controlled under 0A501.d or 0A501.x, depending on the magazine's capacity.</em></p></div><p>e. Receivers (frames) and \"complete breech mechanisms,\" including castings, forgings, stampings, or machined items thereof, \"specially designed\" for a commodity controlled by paragraph .a or .b of this entry.</p><div class=\"note\"><div class=\"header\"><em>Note 4 to 0A501.e:</em></div><p><em>Frames (receivers) under 0A501.e refers to any \"part\" or \"component\" of the firearm that has or is customarily marked with a serial number when required by law. This paragraph 0A501.e is synonymous with a \"part\" or \"component\" that is regulated by the Bureau of Alcohol, Tobacco, Firearms and Explosives (see <a href=\"https://www.govinfo.gov/link/uscode/18/921\" class=\"usc external\" target=\"_blank\" rel=\"noopener noreferrer\">18 U.S.C. 921(a)(3)</a>; <a href=\"https://www.ecfr.gov/current/title-27/part-447\" class=\"cfr external\">27 CFR parts 447</a>, <a href=\"https://www.ecfr.gov/current/title-27/part-478\" class=\"cfr external\">478</a>, and <a href=\"https://www.ecfr.gov/current/title-27/part-479\" class=\"cfr external\">479</a>,) as a firearm.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 5 to 0A501.e:</em></div><p><em>Frames (receivers) \"specially designed\" for semi-automatic firearms are controlled under ECCN 0A509.b or .c.</em></p></div><p>f. through w. [Reserved]</p><p>x. \"Parts\" and \"components\" that are \"specially designed\" for a commodity classified under paragraphs .a through .c of this entry, a commodity classified under ECCNs 0A506 or 0A507, or the USML and not elsewhere specified on the USML or CCL or controlled under ECCN 0A509.</p><p>y. Specific \"parts,\" \"components,\" \"accessories\" and \"attachments\" \"specially designed\" for a commodity subject to control in this ECCN, ECCNs 0A506, 0A507, or common to a defense article in USML Category I and not elsewhere specified in the USML or CCL as follows, and \"parts,\" \"components,\" \"accessories,\" and \"attachments\" \"specially designed\" therefor.</p><p>y.1. Stocks (including adjustable, collapsible, blades and braces), grips, handguards, or forends, that do not contain any fire control \"parts\" or \"components\" (<em>e.g.,</em> triggers, hammers/striker, sears, disconnectors);</p><p>y.2 through y.5. [Reserved]</p><p>y.6. Bayonets; and</p><p>y.7. Firearms manufactured from 1890 to 1898 and reproductions thereof.</p><div class=\"note\"><div class=\"header\"><em>Technical Note 1 to 0A501:</em></div><p><em>ECCN 0A501 includes \"parts\" and \"components\" that are not \"subject to the ITAR\" even though they are common to firearms described in ECCN 0A501 and to those firearms \"subject to the ITAR.\"</em></p></div><div class=\"note\"><div class=\"header\"><em>Technical Note 2 to 0A501:</em></div><p><em>A receiver with any other controlled \"part\" or \"component\" ( e.g., a barrel (0A501.c), or trigger guard (0A501.x), or stock (0A501.y.1)) is still controlled under 0A501.e.</em></p></div><div class=\"note\"><div class=\"header\"><em>Technical Note 3 to 0A501:</em></div><p><em>Blank firing adapters, which are attachments to semi-automatic and automatic firearms used in conjunction with blank cartridges for safety and functional reasons and used for firearm training purposes by police, military, sporting shooters, as well as in the movie industry, are designated as EAR99.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 6 to 0A501:</em></div><p><em>Antique firearms (i.e., those manufactured before 1890) and reproductions thereof, muzzle loading and black powder firearms except those designs based on centerfire weapons of a post 1937 design, BB guns, pellet rifles, paint ball, and all other air rifles are EAR99 commodities.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 7 to 0A501:</em></div><p><em>Muzzle loading and black powder firearms with a caliber less than 20 mm that were manufactured post 1937 that are used for hunting or sporting purposes that were not \"specially designed\" for military use and are not described on the USML nor controlled as shotguns under ECCN 0A502 are EAR99 commodities.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 8 to 0A501:</em></div><p><em>Scope mounts or accessory rails, iron sights, sling swivels, and butt plates or recoil pads that are subject to the EAR are designated as EAR99. These commodities have been determined to no longer warrant being \"specially designed\" for purposes of ECCN 0A501.</em></p></div><div class=\"note\"><div class=\"header\"><em>Note 9 to 0A501:</em></div><p><em>A kit, including a replacement or repair kit, of firearms \"parts\" or \"components\" customarily sold and exported together takes on the classification of the most restrictive \"part\" or \"component\" that is included in the kit. For example, a kit containing 0A501.y and .x \"parts,\" is controlled as a 0A501.x kit because the .x \"part\" is the most restrictive \"part\" included in the kit. A complete 0A501 firearm disassembled in a kit form is controlled as a firearm under 0A501.a, .b, or .y.7.</em></p></div>",
// "cclChildren": null
// },
// {
// "id": 3,
// "cclCode": "0A502",
// "cclTitle": "Shotguns; shotguns \"parts\" and \"components,\" consisting of complete trigger mechanisms; magazines and magazine extension tubes; \"complete breech mechanisms;\" except: semi-automatic shotguns controlled under Eccn 0A508; certain \"parts,\" components,\" devices, \"accessories,\" and \"attachments\" for semi-automatic shotguns controlled under Eccn 0A509; equipment used to slaughter domestic animals or used exclusively to treat or tranquilize animals; and arms designed solely for signal, flare, or saluting use.",
// "cclTitleZh": "霰弹枪;霰弹枪“零件”和“组件”,由完整的扳机机构组成;弹药库和弹匣延长管;“完整的闭锁机构”;除外:根据 Eccn 0A508 控制的半自动霰弹枪;根据 Eccn 0A509 控制的某些半自动霰弹枪的“零件”、“组件”、“装置”、“配件”;用于屠宰家畜或专门用于治疗或镇静动物的设备;以及仅用于信号、照明或敬礼使用的武器。",
// "cclDescription": null,
// "cclDescriptionZh": null,
// "cclChildren": null
// }
// ]
// }
// ]
// }
// ]
// }
// cclList.value = res.data
// // 给数据添加isExpand字段
// cclList.value.forEach((item) => {
// item.isExpand = false
// item.cclChildren.forEach((ele) => {
// ele.cclChildren.forEach((i) => {
// i.isExpand = false
// })
// })
// })
if (res && res.code === 200) {
console.log("----getCclList", res.data);
cclList.value = res.data;
......@@ -269,30 +223,100 @@ const getCCLVersionListApi = async () => {
console.error("获取清单版本列表失败:", error);
}
};
const allReasonChecked = ref(false);
const allTechFieldsChecked = ref(false);
const allControlReasonChecked = ref(false);
// 筛选逻辑处理
// 筛选逻辑处理
const handleFilterChange = (item, list, type) => {
console.log(item, list, type);
if (type === "tech") {
if (item.id == "0") {
if (item.checked) {
list.forEach((field, index) => {
if (index !== 0) field.checked = false;
});
} else {
if (list.length > 1) {
list[1].checked = true;
for (let i = 2; i < list.length; i++) {
list[i].checked = false;
}
}
}
} else {
const allItem = list[0];
if (allItem) {
allItem.checked = false;
}
}
} else if (type === "reason") {
// 👇 新增:对 controlReason 做同样处理
if (item.id == "0") {
if (item.checked) {
// 选中“全部等级” → 取消其他
list.forEach((field, index) => {
if (index !== 0) field.checked = false;
});
} else {
// 取消“全部等级” → 选中 index=1
if (list.length > 1) {
list[1].checked = true;
for (let i = 2; i < list.length; i++) {
list[i].checked = false;
}
}
}
} else {
// 点击非“全部”项 → 取消“全部”
const allItem = list[0];
if (allItem) {
allItem.checked = false;
}
}
}
getCclList();
};
watch(viewNew, newValue => {
// 处理“科技领域-全部”复选框变化
const handleAllTechFieldsChange = checked => {
if (checked) {
// 全选:所有 techFields.checked = true
techFields.value.forEach(item => (item.checked = true));
} else {
// 取消全选:只保留第一个选中
techFields.value.forEach((item, index) => {
item.checked = index === 0;
});
}
// 触发数据刷新
getCclList();
});
};
watch(currentCCLVersion, newValue => {
console.log(newValue);
getCclList();
});
watch(currentCCLType, newValue => {
console.log(newValue);
getCclList();
});
watch(searchKeyworn, newValue =>{
// 处理“管控原因-全部”复选框变化
const handleAllControlReasonChange = checked => {
if (checked) {
controlReason.value.forEach(item => (item.checked = true));
} else {
controlReason.value.forEach((item, index) => {
item.checked = index === 0;
});
}
getCclList();
});
};
// watch(viewNew, newValue => {
// getCclList();
// });
// watch(currentCCLType, newValue => {
// console.log(newValue);
// getCclList();
// });
// watch(currentCCLVersion, newValue => {
// console.log(newValue);
// getCclList();
// });
// const searchDebounceTimer = ref(null);
// watch(searchKeyword, () => {
......@@ -304,10 +328,21 @@ watch(searchKeyworn, newValue =>{
// getExportControlListApi();
// }, 300);
// });
watch(searchKeyword, newValue => {
console.log("-----searchKey", newValue);
// watch(searchKeyword, newValue => {
// console.log("-----searchKey", newValue);
// getCclList();
// });
watch(
[viewNew, currentCCLType, currentCCLVersion, searchKeyword],
([newViewNew, newType, newVersion, newKeyword], [oldViewNew, oldType, oldVersion, oldKeyword]) => {
// 可选:判断是否是真正有意义的变化(避免初始赋值触发)
if (newViewNew !== oldViewNew || newType !== oldType || newVersion !== oldVersion || newKeyword !== oldKeyword) {
getCclList();
});
}
},
{ immediate: false } // 如果不需要初始触发,设为 false(默认)
);
// 模拟清单列表
const cclList = ref([
......@@ -376,6 +411,9 @@ onMounted(async () => {
:deep(.el-input__wrapper) {
padding: 0 11px;
border: 1px solid #dcdfe6;
background-color: #fff;
border-radius: 4px;
}
:deep(.el-input__inner) {
......@@ -708,7 +746,10 @@ onMounted(async () => {
.btn-next {
border: 1px solid #dcdfe6;
border-radius: 4px;
padding
padding: 0;
margin: 0 4px;
min-width: 32px;
height: 32px;
line-height: 30px;
text-align: center;
......@@ -731,7 +772,8 @@ onMounted(async () => {
.title {
width: 100%;
height: 56px;
display: flr;
display: flex;
align-items: center;
padding: 14px 12px 16px 0;
display: flex;
align-items: center;
......
......@@ -31,7 +31,7 @@
<div class="info-row">
<div class="label">发布人:</div>
<div class="value link">
<img :src="defaultTitle" alt="" class="icon avatar" />
<img :src="formattedData.avartarUrl" alt="" class="icon avatar" />
<span @click="handleClick">{{ formattedData.postPersonName }} ></span>
</div>
</div>
......@@ -46,7 +46,7 @@
<div class="content-title">制裁实体分布:</div>
<div class="distribution-list">
<div class="list-item" v-for="(item, index) in entityDistribution" :key="index">
<img :src="flag" alt="" class="flag" />
<img :src="item.imageUrl || flag" alt="" class="flag" />
<div class="country-name">{{ item.name }}</div>
<div class="progress-bar-container">
<div
......@@ -152,6 +152,7 @@
</div>
<div class="right-content">
<div class="sanction-group-list">
<el-empty v-if="sanctionList.length === 0" description="暂无制裁清单数据" />
<div class="sanction-group" v-for="(group, index) in sanctionList" :key="index">
<el-table :data="group.entities" style="width: 100%">
<el-table-column label="实体名称" min-width="280">
......@@ -302,7 +303,7 @@ const getSanctionOverviewList = async () => {
removeCount.value = data.removeCount || 0;
removeRuleCount.value = data.removeRuleCount || 0;
const list = data.sanList || [];
const list = searchType.value == "add" ? data.sanList : data.removeList || [];
sanctionList.value = list.map(item => ({
reason: item.sanReason,
entities: (item.orgList || []).map(org => ({
......@@ -448,7 +449,8 @@ const formattedData = computed(() => {
fileCode: info.fileCode ? `${info.fileCode} ` : "",
administrativeOrderId: info.administrativeOrderId ? `No. ${info.administrativeOrderId}` : "",
postPersonName: info.postPersonName,
domains: info.domainNames
domains: info.domainNames,
avartarUrl: info.postPersonAvatarUrl
};
});
......
......@@ -13,8 +13,14 @@
</div> -->
<div class="home-main-header-center">
<SearchContainer class="think-tank-search" style="margin-bottom: 0; margin-top: 51px; height: fit-content;"
v-if="containerRef" placeholder="搜索智库、报告或政策建议" :containerRef="containerRef" areaName="智库" />
<SearchContainer
class="think-tank-search"
style="margin-bottom: 0; margin-top: 51px; height: fit-content"
v-if="containerRef"
placeholder="搜索智库、报告或政策建议"
:containerRef="containerRef"
areaName="智库"
/>
<!-- <el-input v-model="searchThinktankText" @keyup.enter="handleSearch"
style="width: 838px; height: 100%" placeholder="搜索智库报告" />
<div class="search">
......@@ -57,8 +63,9 @@
</div>
<div class="home-main-header-card-box">
<div class="card" v-for="(item, index) in sortedCardList" :key="index" @click="handleClick(item)">
<div class="red-info" v-if="item.increaseReportNumber != 0 && item.increaseReportNumber != null">{{ "+" }}{{
item.increaseReportNumber }}</div>
<div class="red-info" v-if="item.increaseReportNumber != 0 && item.increaseReportNumber != null">
{{ "+" }}{{ item.increaseReportNumber }}
</div>
<div class="card-header">
<div class="icon">
<img :src="item.logo" alt="" />
......@@ -67,8 +74,7 @@
{{ "No." + (index + 1) }}
</div> -->
<div class="rank">
<div class=" number">{{ item.reportNumber }} {{ "篇报告" }}</div>
<div class="number">{{ item.reportNumber }} {{ "篇报告" }}</div>
</div>
</div>
<div class="card-title">
......@@ -122,8 +128,14 @@
</div>
<div class="box1-header-right" @click="handleClickToDetail">查看详情 ></div>
</div>
<el-carousel ref="carouselRef" height="395px" :autoplay="true" :interval="3000" arrow="never"
indicator-position="none">
<el-carousel
ref="carouselRef"
height="395px"
:autoplay="true"
:interval="3000"
arrow="never"
indicator-position="none"
>
<el-carousel-item v-for="(itemData, index) in box1Data" :key="index">
<div class="box1-main">
<div class="box1-main-left">
......@@ -132,7 +144,6 @@
<div class="box1-main-right">
<div class="title">{{ itemData?.reportName }}</div>
<div class="name">
<div class="logo-title-box">
<div class="logo">
......@@ -148,8 +159,11 @@
<!-- <div class="tag" v-for="(item, index) in itemData?.industryVOList" :key="index">
{{ item.industryName }}
</div> -->
<AreaTag v-for="(item, index) in itemData?.industryVOList" :key="index"
:tagName="item.industryName">
<AreaTag
v-for="(item, index) in itemData?.industryVOList"
:key="index"
:tagName="item.industryName"
>
</AreaTag>
</div>
</div>
......@@ -158,15 +172,34 @@
</el-carousel-item>
</el-carousel>
</div>
<RiskSignal :list="warningList" @more-click="handleToMoreRiskSignal" postDate="time" name="title"
@item-click="handleClickToDetail" />
<RiskSignal
:list="warningList"
@more-click="handleToMoreRiskSignal"
postDate="time"
name="title"
@item-click="handleClickToDetail"
/>
</div>
<DivideHeader id="position2" class="divide-header" :titleText="'资讯要闻'"></DivideHeader>
<div class="center-center">
<NewsList :newsList="newsList" @item-click="handleToNewsAnalysis" @more-click="handleToMoreNews"
img="newsImage" title="newsTitle" content="newsContent" from="from" />
<MessageBubble :messageList="messageList" imageUrl="personImage" @more-click="handleToSocialDetail"
@person-click="handleClickPerson" name="personName" content="remarks" source="orgName" />
<NewsList
:newsList="newsList"
@item-click="handleToNewsAnalysis"
@more-click="handleToMoreNews"
img="newsImage"
title="newsTitle"
content="newsContent"
from="from"
/>
<MessageBubble
:messageList="messageList"
imageUrl="personImage"
@more-click="handleToSocialDetail"
@person-click="handleClickPerson"
name="personName"
content="remarks"
source="orgName"
/>
</div>
<DivideHeader id="position3" class="divide-header" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer">
......@@ -179,16 +212,33 @@
<div class="box5-header-title">{{ "数量变化趋势" }}</div>
</div>
<div class="box5-select-box">
<el-select v-model="box5selectetedArea" placeholder="选择领域" style="width: 120px"
@change="handleBox5AreaChange">
<el-select
v-model="box5selectetedArea"
placeholder="选择领域"
style="width: 120px"
@change="handleBox5AreaChange"
>
<el-option label="全部领域" value="全部领域" />
<el-option v-for="item in box5RawData.data" :key="item.name" :label="item.name" :value="item.name" />
<el-option
v-for="item in box5RawData.data"
:key="item.name"
:label="item.name"
:value="item.name"
/>
</el-select>
<el-select v-model="box5selectetedYear" placeholder="选择年份" style="width: 120px"
@change="changeBox5Data">
<el-option v-for="item in box5YearList" :key="item.value" :label="item.label" :value="item.value" />
<el-select
v-model="box5selectetedYear"
placeholder="选择年份"
style="width: 120px"
@change="changeBox5Data"
>
<el-option
v-for="item in box5YearList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</div>
<div class="box5-main" :class="{ 'box5-main--empty': !hasBox5ChartData }">
......@@ -203,11 +253,18 @@
<TipTab :text="'智库报告数量变化趋势,数据来源:美国各智库官网'" />
</div>
<div class="chart-box">
<div class="btn-box" v-if="!isShowAiContentBox5" @mouseenter="handleSwitchAiContentShowBox5(true)">
<div
class="btn-box"
v-if="!isShowAiContentBox5"
@mouseenter="handleSwitchAiContentShowBox5(true)"
>
<AiButton />
</div>
<div class="content-box" v-if="isShowAiContentBox5"
@mouseleave="handleSwitchAiContentShowBox5(false)">
<div
class="content-box"
v-if="isShowAiContentBox5"
@mouseleave="handleSwitchAiContentShowBox5(false)"
>
<AiPane :aiContent="aiContentBox5" />
</div>
</div>
......@@ -223,13 +280,22 @@
<div class="box6-select-box">
<el-select v-model="box6selectetedTank" placeholder="选择智库" style="width: 120px">
<el-option label="全部智库" value="全部智库" />
<el-option v-for="item in box6TankList" :key="item.value" :label="item.label" :value="item.value" />
<el-option
v-for="item in box6TankList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-select v-model="box6selectetedYear" placeholder="选择时间" style="width: 120px">
<el-option v-for="item in box6YearList" :key="item.value" :label="item.label" :value="item.value"
@click="handleBox6()" />
<el-option
v-for="item in box6YearList"
:key="item.value"
:label="item.label"
:value="item.value"
@click="handleBox6()"
/>
</el-select>
</div>
</div>
......@@ -243,11 +309,18 @@
<TipTab :text="'智库报告领域分布情况,数据来源:美国各智库官网'" />
</div>
<div class="chart-box">
<div class="btn-box" v-if="!isShowAiContentBox6" @mouseenter="handleSwitchAiContentShowBox6(true)">
<div
class="btn-box"
v-if="!isShowAiContentBox6"
@mouseenter="handleSwitchAiContentShowBox6(true)"
>
<AiButton />
</div>
<div class="content-box" v-if="isShowAiContentBox6"
@mouseleave="handleSwitchAiContentShowBox6(false)">
<div
class="content-box"
v-if="isShowAiContentBox6"
@mouseleave="handleSwitchAiContentShowBox6(false)"
>
<AiPane :aiContent="aiContentBox6" />
</div>
</div>
......@@ -275,11 +348,18 @@
<TipTab :text="'美国科技智库与主要政府机构之间的资金往来,数据来源:美国各智库官网'" />
</div>
<div class="chart-box">
<div class="btn-box" v-if="!isShowAiContentBox7" @mouseenter="handleSwitchAiContentShowBox7(true)">
<div
class="btn-box"
v-if="!isShowAiContentBox7"
@mouseenter="handleSwitchAiContentShowBox7(true)"
>
<AiButton />
</div>
<div class="content-box" v-if="isShowAiContentBox7"
@mouseleave="handleSwitchAiContentShowBox7(false)">
<div
class="content-box"
v-if="isShowAiContentBox7"
@mouseleave="handleSwitchAiContentShowBox7(false)"
>
<AiPane :aiContent="aiContentBox7" />
</div>
</div>
......@@ -294,19 +374,22 @@
</div>
<div class="box8-header-title">{{ "智库研究热点" }}</div>
</div>
</div>
<div class="box8-main">
<div class="box8-main-item">
<div class="box8-item" v-for="(item, index) in box8Data" :key="index">
<div class="item-left"
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }">
<div
class="item-left"
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }"
>
{{ index + 1 }}
</div>
<!-- <el-popover effect="dark" :content="item.clause" placement="top-start">
<template #reference> -->
<div class="item-center"
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }">
<div
class="item-center"
:class="{ itemBold1: index === 0, itemBold2: index === 1, itemBold3: index === 2 }"
>
{{ item.clause }}
</div>
<!-- </template>
......@@ -315,9 +398,7 @@
<!-- <div class="item-right">{{ `${item.count}份报告 >` }}</div> -->
<div class="item-count">{{ item.count + "份报告 >" }}</div>
</div>
</div>
</div>
</div>
</div>
......@@ -328,21 +409,42 @@
<div class="home-main-footer-header">
<div class="btn-box">
<div class="btn" :class="{ btnActive: activeCate === cate }" v-for="(cate, index) in categoryList"
:key="index" @click="handleClickCate(cate)">
<div
class="btn"
:class="{ btnActive: activeCate === cate }"
v-for="(cate, index) in categoryList"
:key="index"
@click="handleClickCate(cate)"
>
{{ cate }}
</div>
</div>
<div class="select-box">
<el-select v-model="resourceLibrarySortModel" class="resource-library-sort-select" placeholder="发布时间"
style="width: 120px" :teleported="true" placement="bottom-start"
:popper-options="resourceLibrarySortPopperOptions" @change="handleResourceLibrarySortChange">
<el-select
v-model="resourceLibrarySortModel"
class="resource-library-sort-select"
placeholder="发布时间"
style="width: 120px"
:teleported="true"
placement="bottom-start"
:popper-options="resourceLibrarySortPopperOptions"
@change="handleResourceLibrarySortChange"
>
<template #prefix>
<img v-if="resourceLibrarySortModel !== true"
<img
v-if="resourceLibrarySortModel !== true"
src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image down.png"
class="resource-library-sort-prefix-img" alt="" @click.stop="toggleResourceLibrarySortPrefix" />
<img v-else src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image up.png"
class="resource-library-sort-prefix-img" alt="" @click.stop="toggleResourceLibrarySortPrefix" />
class="resource-library-sort-prefix-img"
alt=""
@click.stop="toggleResourceLibrarySortPrefix"
/>
<img
v-else
src="@/views/thinkTank/ThinkTankDetail/thinkDynamics/images/image up.png"
class="resource-library-sort-prefix-img"
alt=""
@click.stop="toggleResourceLibrarySortPrefix"
/>
</template>
<el-option :key="'resource-lib-sort-asc'" label="正序" :value="true" />
<el-option :key="'resource-lib-sort-desc'" label="倒序" :value="false" />
......@@ -354,25 +456,54 @@
</el-select> -->
</div>
<div class="resource-library-content">
<HomeMainFooterMain v-if="activeCate === '智库报告'" :area-list="areaList"
v-model:selectedAreaList="selectedAreaList" :pub-time-list="pubTimeList"
v-model:selectedPubTimeList="selectedPubTimeList" @filter-change="handleThinkTankReportFilterChange"
:cur-footer-list="curFooterList" :total="total" :current-page="currentPage"
@report-click="handleToReportDetail" @page-change="handleCurrentChange" />
<HomeMainFooterSurvey v-else-if="activeCate === '调查项目'" :area-list="areaList"
v-model:selectedAreaList="surveySelectedAreaList" :pub-time-list="pubTimeList"
v-model:selectedPubTimeList="surveySelectedPubTimeList" @filter-change="handleSurveyFilterChange"
:cur-footer-list="surveyFooterList" :total="surveyTotal" :current-page="surveyCurrentPage"
@report-click="handleToReportDetail" @page-change="handleSurveyCurrentChange" />
<ThinkTankCongressHearingOverview v-else-if="activeCate === '国会听证会'" :key="`congress-${resourceTabResetKey}`"
:research-type-list="areaList" :research-time-list="pubTimeList" @report-click="handleToReportDetail" />
<ThinkTankPolicyAdviceOverview v-else :key="`policy-${resourceTabResetKey}`" :research-type-list="areaList"
:research-time-list="pubTimeList" :list="policyFooterList" :total="policyTotal"
:current-page="policyCurrentPage" :page-size="7" @filter-change="handlePolicyFilterChange"
@page-change="handlePolicyCurrentChange" />
<HomeMainFooterMain
v-if="activeCate === '智库报告'"
:area-list="areaList"
v-model:selectedAreaList="selectedAreaList"
:pub-time-list="pubTimeList"
v-model:selectedPubTimeList="selectedPubTimeList"
@filter-change="handleThinkTankReportFilterChange"
:cur-footer-list="curFooterList"
:total="total"
:current-page="currentPage"
@report-click="handleToReportDetail"
@page-change="handleCurrentChange"
/>
<HomeMainFooterSurvey
v-else-if="activeCate === '调查项目'"
:area-list="areaList"
v-model:selectedAreaList="surveySelectedAreaList"
:pub-time-list="pubTimeList"
v-model:selectedPubTimeList="surveySelectedPubTimeList"
@filter-change="handleSurveyFilterChange"
:cur-footer-list="surveyFooterList"
:total="surveyTotal"
:current-page="surveyCurrentPage"
@report-click="handleToReportDetail"
@page-change="handleSurveyCurrentChange"
/>
<ThinkTankCongressHearingOverview
v-else-if="activeCate === '国会听证会'"
:key="`congress-${resourceTabResetKey}`"
:research-type-list="areaList"
:research-time-list="pubTimeList"
@report-click="handleToReportDetail"
/>
<ThinkTankPolicyAdviceOverview
v-else
:key="`policy-${resourceTabResetKey}`"
:research-type-list="areaList"
:research-time-list="pubTimeList"
:list="policyFooterList"
:total="policyTotal"
:current-page="policyCurrentPage"
:page-size="7"
@filter-change="handlePolicyFilterChange"
@page-change="handlePolicyCurrentChange"
/>
</div>
</div>
</div>
......@@ -382,7 +513,7 @@
<script setup>
import RiskSignal from "@/components/base/riskSignal/index.vue";
import NewsList from "@/components/base/newsList/index.vue";
import MessageBubble from "@/components/base/MessageBubble/index.vue"
import MessageBubble from "@/components/base/MessageBubble/index.vue";
import { onMounted, ref, computed, reactive, nextTick } from "vue";
import scrollToTop from "@/utils/scrollToTop";
import router from "@/router";
......@@ -420,8 +551,8 @@ import News2 from "./assets/images/news2.png";
import News3 from "./assets/images/news3.png";
import News4 from "./assets/images/news4.png";
import News5 from "./assets/images/news5.png";
import AiButton from '@/components/base/Ai/AiButton/index.vue'
import AiPane from '@/components/base/Ai/AiPane/index.vue'
import AiButton from "@/components/base/Ai/AiButton/index.vue";
import AiPane from "@/components/base/Ai/AiPane/index.vue";
import TipTab from "./TipTab/index.vue";
import {
RESOURCE_FILTER_ALL_AREA,
......@@ -461,15 +592,15 @@ import Box1Img from "./assets/images/box1-img.png";
import Box1Logo from "./assets/images/box1-logo.png";
import { setCanvasCreator } from "echarts/core";
import { ElMessage } from "element-plus";
import { useRouter } from 'vue-router';
import { useRouter } from "vue-router";
const containerRef = ref(null);
const statCountInfo = ref([]);
const pageSize = ref(15)
const totalAllItem = ref(0)
const pageSize = ref(15);
const totalAllItem = ref(0);
const isShowAiContentBox5 = ref(false);
const aiContentBox5 = ref("");
const isBox5InterpretLoading = ref(false);
const handleSwitchAiContentShowBox5 = (val) => {
const handleSwitchAiContentShowBox5 = val => {
isShowAiContentBox5.value = val;
if (val) {
fetchBox5ChartInterpretation();
......@@ -478,7 +609,7 @@ const handleSwitchAiContentShowBox5 = (val) => {
const isShowAiContentBox6 = ref(false);
const aiContentBox6 = ref("");
const isBox6InterpretLoading = ref(false);
const handleSwitchAiContentShowBox6 = (val) => {
const handleSwitchAiContentShowBox6 = val => {
isShowAiContentBox6.value = val;
if (val) {
fetchBox6ChartInterpretation();
......@@ -487,7 +618,7 @@ const handleSwitchAiContentShowBox6 = (val) => {
const isShowAiContentBox7 = ref(false);
const aiContentBox7 = ref("");
const isBox7InterpretLoading = ref(false);
const handleSwitchAiContentShowBox7 = (val) => {
const handleSwitchAiContentShowBox7 = val => {
isShowAiContentBox7.value = val;
if (val) {
fetchBox7ChartInterpretation();
......@@ -504,40 +635,36 @@ const handleGetAllThinkTankList = async () => {
console.log("智库列表", res);
if (res.code === 200 && res.data) {
totalAllItem.value = res.data.totalElements;
}
} catch (error) {
console.error("获取智库列表error", error);
}
};
const routerTo = useRouter()
const routerTo = useRouter();
// 跳转到全部智库页面
const goToAllThinkTank = () => {
// 替换为你的实际路由路径
routerTo.push('/thinkTank/allThinkTank');
routerTo.push("/thinkTank/allThinkTank");
};
const timePeriod = ref("WEEK")
const timePeriod = ref("WEEK");
const handleTimeClick = item => {
const time = item?.time
const time = item?.time;
if (time === "近一周") {
timePeriod.value = "WEEK"
timePeriod.value = "WEEK";
} else if (time === "近一月") {
timePeriod.value = "MONTH"
timePeriod.value = "MONTH";
} else if (time === "近一年") {
timePeriod.value = "YEAR"
timePeriod.value = "YEAR";
}
// 切换时间范围后重新拉取(从第一页开始)
currentPage.value = 1
handleGetAllThinkTankList()
currentPage.value = 1;
handleGetAllThinkTankList();
// 同步刷新首页卡片数据(包含 increaseReportNumber)
handleGetThinkTankList()
}
handleGetThinkTankList();
};
const getStatCountInfo = async () => {
// console.log('----getStatCountInfo', res.data)
statCountInfo.value = [
{
......@@ -557,8 +684,6 @@ const getStatCountInfo = async () => {
count: "2"
}
];
};
const searchThinktankText = ref(""); //搜索科技人物及观点
// 智库列表
......@@ -623,7 +748,7 @@ const handleGetThinkTankList = async () => {
// 兼容两种返回结构:
// 1) data.content(分页)
// 2) data 直接是数组(非分页)
const list = Array.isArray(res.data) ? res.data : (res.data?.content || []);
const list = Array.isArray(res.data) ? res.data : res.data?.content || [];
cardList.value = list.map(item => ({
id: item.id,
logo: item.imageUrl,
......@@ -659,17 +784,16 @@ const handleGetNewReport = async () => {
console.log("智库发布", res);
if (res.code === 200 && res.data) {
box1Data.value = res.data.map(item => {
const formatDate = (dateStr) => {
if (!dateStr) return ''; // 处理空值,避免报错
const [year, month, day] = dateStr.split('-');
const formatDate = dateStr => {
if (!dateStr) return ""; // 处理空值,避免报错
const [year, month, day] = dateStr.split("-");
return `${year}${parseInt(month, 10)}${parseInt(day, 10)}日`;
};
return {
...item,
reportDate: formatDate(item.reportDate)
}
})
};
});
}
} catch (error) {
console.error("获取智库列表error", error);
......@@ -1029,16 +1153,10 @@ const handleBox5 = async year => {
};
/** 兼容 getChartAnalysis 返回对象:从 data[0] 提取「解读」文本 */
const getInterpretationTextFromChartResponse = (res) => {
const getInterpretationTextFromChartResponse = res => {
const list = res?.data;
const first = Array.isArray(list) ? list[0] : null;
return (
first?.["解读"] ||
first?.["interpretation"] ||
first?.["analysis"] ||
first?.["content"] ||
""
);
return first?.["解读"] || first?.["interpretation"] || first?.["analysis"] || first?.["content"] || "";
};
/** 参考科技法案数量变化趋势:按 chunk 增量拼接展示 */
......@@ -1073,7 +1191,7 @@ const fetchBox5ChartInterpretation = async () => {
name: "数量变化趋势",
data: v.title.map((label, i) => {
const point = { period: label };
v.data.forEach((s) => {
v.data.forEach(s => {
point[s.name] = s.value[i] ?? 0;
});
return point;
......@@ -1186,9 +1304,7 @@ const box6PieDisplayData = computed(() => {
/** 饼图解读用数据:排除占位项 */
const getBox6InterpretationSeries = () => {
const pie = box6PieDisplayData.value;
return pie.filter(
item => item.name !== "暂无数据" && item.name !== "暂无该领域数据"
);
return pie.filter(item => item.name !== "暂无数据" && item.name !== "暂无该领域数据");
};
/** 请求 box6 领域分布饼图解读(入参:{ text: JSON.stringify({ type, name, data }) },与柱状图示例同结构) */
......@@ -1236,9 +1352,7 @@ const fetchBox6ChartInterpretation = async () => {
}
};
const box6AreaList = ref([
]);
const box6AreaList = ref([]);
const box6selectetedTank = ref("全部智库");
const box6TankList = ref([
{
......@@ -1543,25 +1657,25 @@ const handleGetThinkTankHot = async date => {
// 资源库
const categoryList = ref(["智库报告", "调查项目", "国会听证会", "政策建议"]);
const activeCate = ref("智库报告");
const resourceTabResetKey = ref(0)
const resourceTabResetKey = ref(0);
const resetResourceTabCommon = () => {
// 统一回到“刷新后刚加载出来的状态”
// 分页归 1,排序占位「发布时间」且默认倒序(null),与智库动态一致
currentPage.value = 1
sort.value = null
currentPage.value = 1;
sort.value = null;
surveyCurrentPage.value = 1
surveySort.value = null
surveyCurrentPage.value = 1;
surveySort.value = null;
policyCurrentPage.value = 1
policySort.value = null
policyCurrentPage.value = 1;
policySort.value = null;
congressResourceSort.value = null
congressResourceSort.value = null;
// 强制重置那些在子组件内部维护状态的组件(国会听证会/政策建议筛选)
resourceTabResetKey.value += 1
}
resourceTabResetKey.value += 1;
};
const resetThinkTankReportFilters = () => {
selectedAreaList.value = [RESOURCE_FILTER_ALL_AREA];
......@@ -1583,19 +1697,19 @@ const handleClickCate = cate => {
activeCate.value = cate;
// 切换到不同分类时,触发对应数据加载,且互不影响
if (cate === "智库报告") {
resetResourceTabCommon()
resetThinkTankReportFilters()
resetResourceTabCommon();
resetThinkTankReportFilters();
handleGetetThinkTankReport();
} else if (cate === "调查项目") {
resetResourceTabCommon()
resetSurveyFilters()
resetResourceTabCommon();
resetSurveyFilters();
handleGetThinkTankSurvey();
} else if (cate === "政策建议") {
resetResourceTabCommon()
resetPolicyFilters()
resetResourceTabCommon();
resetPolicyFilters();
handleGetThinkTankPolicyAdvice();
} else if (cate === "国会听证会") {
resetResourceTabCommon()
resetResourceTabCommon();
}
};
......@@ -1831,7 +1945,7 @@ const handleSurveyCurrentChange = page => {
const handleGetThinkTankSurvey = async () => {
const { startDate, endDate } = getResourceLibraryReportDateRangeFromTimeSelection(
stripAllTimeForRequest(surveySelectedPubTimeList.value),
(pubTimeList.value || []).map((x) => x.id)
(pubTimeList.value || []).map(x => x.id)
);
const params = {
pageNum: surveyCurrentPage.value,
......@@ -1839,7 +1953,7 @@ const handleGetThinkTankSurvey = async () => {
sortFun: surveySort.value === true,
domainIds: (() => {
const areas = stripAllAreaForRequest(surveySelectedAreaList.value);
const allAreaIds = (areaList.value || []).map((a) => a.id);
const allAreaIds = (areaList.value || []).map(a => a.id);
if (isSelectionCoveringAllOptions(areas, allAreaIds)) {
return "";
}
......@@ -1886,31 +2000,162 @@ const handlePolicyCurrentChange = page => {
};
const handleGetThinkTankPolicyAdvice = async () => {
const mockPolicyAdviceList = () => ([
const mockPolicyAdviceList = () => [
{
id: 23702,
content: "研究未来AI数据中心电力需求与供应",
imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "指数级增长下AI的电力需求:外推AI数据中心的电力需求并评估其对美国竞争力的潜在影响",
reportId: "Rand_RRA3572-1",
tagList: ["新能源", "人工智能"],
thinkTankName: null,
times: "2025-12-28"
},
{ id: 23703, content: "构建可信任的AI治理框架:监管与创新的平衡", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "AI治理路线图:从风险评估到合规落地的实践建议", reportId: "Rand_RRA3572-2", tagList: ["人工智能", "网络安全"], thinkTankName: null, times: "2025-12-21" },
{ id: 23704, content: "先进制造供应链韧性评估与关键节点识别", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "供应链韧性:关键材料、关键设备与关键人才的系统性策略", reportId: "Rand_RRA3572-3", tagList: ["先进制造", "新材料"], thinkTankName: null, times: "2025-12-14" },
{ id: 23705, content: "半导体出口管制对产业生态的中长期影响", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "出口管制与产业政策:如何降低对关键环节的外部依赖", reportId: "Rand_RRA3572-4", tagList: ["集成电路", "先进制造"], thinkTankName: null, times: "2025-12-07" },
{ id: 23706, content: "量子信息技术发展态势与应用落地路径", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "量子科技:从基础研究到产业化的阶段性里程碑", reportId: "Rand_RRA3572-5", tagList: ["量子科技", "前沿基础"], thinkTankName: null, times: "2025-11-30" },
{ id: 23707, content: "网络安全威胁图谱:关键基础设施的攻击面", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "关键基础设施安全:供应链、身份与数据的三重防护", reportId: "Rand_RRA3572-6", tagList: ["网络安全", "数据安全"], thinkTankName: null, times: "2025-11-23" },
{ id: 23708, content: "生物技术与医疗创新的监管协同机制", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "生物科技创新:试验、审批与产业化的全流程政策工具箱", reportId: "Rand_RRA3572-7", tagList: ["生物科技", "医疗健康"], thinkTankName: null, times: "2025-11-16" },
{ id: 23709, content: "清洁能源转型下的电网规划与储能配置", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "能源系统转型:电网升级、储能布局与成本测算", reportId: "Rand_RRA3572-8", tagList: ["新能源", "储能"], thinkTankName: null, times: "2025-11-09" },
{ id: 23710, content: "新材料在国防与先进制造中的应用瓶颈", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "关键新材料:验证体系、规模化与供应链安全", reportId: "Rand_RRA3572-9", tagList: ["新材料", "先进制造"], thinkTankName: null, times: "2025-11-02" },
{ id: 23711, content: "通信网络演进:6G 与卫星互联网的融合", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "下一代通信:频谱、标准与产业联盟策略", reportId: "Rand_RRA3572-10", tagList: ["通信网络", "卫星互联网"], thinkTankName: null, times: "2025-10-26" },
{ id: 23712, content: "数据要素市场建设与跨境数据合规路径", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "数据治理与合规:分类分级、出境评估与执法协同", reportId: "Rand_RRA3572-11", tagList: ["数据安全", "数字治理"], thinkTankName: null, times: "2025-10-19" },
{ id: 23713, content: "AI 研发人才供需缺口与教育体系对接", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "AI 人才战略:培养、引进与留用的组合政策", reportId: "Rand_RRA3572-12", tagList: ["人工智能", "人才政策"], thinkTankName: null, times: "2025-10-12" },
{ id: 23714, content: "自动驾驶安全监管与测试评价体系", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "自动驾驶:安全标准、责任划分与道路试点机制", reportId: "Rand_RRA3572-13", tagList: ["智能网联", "交通出行"], thinkTankName: null, times: "2025-10-05" },
{ id: 23715, content: "关键基础设施数字化升级的投融资机制", imageUrl: "https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg", name: "基础设施升级:公共资金撬动与绩效评估体系", reportId: "Rand_RRA3572-14", tagList: ["数字化转型", "基础设施"], thinkTankName: null, times: "2025-09-28" }
]);
{
id: 23703,
content: "构建可信任的AI治理框架:监管与创新的平衡",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "AI治理路线图:从风险评估到合规落地的实践建议",
reportId: "Rand_RRA3572-2",
tagList: ["人工智能", "网络安全"],
thinkTankName: null,
times: "2025-12-21"
},
{
id: 23704,
content: "先进制造供应链韧性评估与关键节点识别",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "供应链韧性:关键材料、关键设备与关键人才的系统性策略",
reportId: "Rand_RRA3572-3",
tagList: ["先进制造", "新材料"],
thinkTankName: null,
times: "2025-12-14"
},
{
id: 23705,
content: "半导体出口管制对产业生态的中长期影响",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "出口管制与产业政策:如何降低对关键环节的外部依赖",
reportId: "Rand_RRA3572-4",
tagList: ["集成电路", "先进制造"],
thinkTankName: null,
times: "2025-12-07"
},
{
id: 23706,
content: "量子信息技术发展态势与应用落地路径",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "量子科技:从基础研究到产业化的阶段性里程碑",
reportId: "Rand_RRA3572-5",
tagList: ["量子科技", "前沿基础"],
thinkTankName: null,
times: "2025-11-30"
},
{
id: 23707,
content: "网络安全威胁图谱:关键基础设施的攻击面",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "关键基础设施安全:供应链、身份与数据的三重防护",
reportId: "Rand_RRA3572-6",
tagList: ["网络安全", "数据安全"],
thinkTankName: null,
times: "2025-11-23"
},
{
id: 23708,
content: "生物技术与医疗创新的监管协同机制",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "生物科技创新:试验、审批与产业化的全流程政策工具箱",
reportId: "Rand_RRA3572-7",
tagList: ["生物科技", "医疗健康"],
thinkTankName: null,
times: "2025-11-16"
},
{
id: 23709,
content: "清洁能源转型下的电网规划与储能配置",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "能源系统转型:电网升级、储能布局与成本测算",
reportId: "Rand_RRA3572-8",
tagList: ["新能源", "储能"],
thinkTankName: null,
times: "2025-11-09"
},
{
id: 23710,
content: "新材料在国防与先进制造中的应用瓶颈",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "关键新材料:验证体系、规模化与供应链安全",
reportId: "Rand_RRA3572-9",
tagList: ["新材料", "先进制造"],
thinkTankName: null,
times: "2025-11-02"
},
{
id: 23711,
content: "通信网络演进:6G 与卫星互联网的融合",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "下一代通信:频谱、标准与产业联盟策略",
reportId: "Rand_RRA3572-10",
tagList: ["通信网络", "卫星互联网"],
thinkTankName: null,
times: "2025-10-26"
},
{
id: 23712,
content: "数据要素市场建设与跨境数据合规路径",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "数据治理与合规:分类分级、出境评估与执法协同",
reportId: "Rand_RRA3572-11",
tagList: ["数据安全", "数字治理"],
thinkTankName: null,
times: "2025-10-19"
},
{
id: 23713,
content: "AI 研发人才供需缺口与教育体系对接",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "AI 人才战略:培养、引进与留用的组合政策",
reportId: "Rand_RRA3572-12",
tagList: ["人工智能", "人才政策"],
thinkTankName: null,
times: "2025-10-12"
},
{
id: 23714,
content: "自动驾驶安全监管与测试评价体系",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "自动驾驶:安全标准、责任划分与道路试点机制",
reportId: "Rand_RRA3572-13",
tagList: ["智能网联", "交通出行"],
thinkTankName: null,
times: "2025-10-05"
},
{
id: 23715,
content: "关键基础设施数字化升级的投融资机制",
imageUrl:
"https://www.rand.org/content/rand/pubs/research_reports/RRA3572-1/jcr:content/par/teaser.crop.1200x900.cm.jpeg/1738160125961.jpeg",
name: "基础设施升级:公共资金撬动与绩效评估体系",
reportId: "Rand_RRA3572-14",
tagList: ["数字化转型", "基础设施"],
thinkTankName: null,
times: "2025-09-28"
}
];
const applyMockPolicyAdvice = () => {
const mock = mockPolicyAdviceList();
policyTotal.value = mock.length;
......@@ -1921,16 +2166,14 @@ const handleGetThinkTankPolicyAdvice = async () => {
};
const strippedPolicyYears = stripAllTimeForRequest(policySelectedYearIds.value);
const allPubTimeIds = (pubTimeList.value || []).map((x) => x.id);
const allPubTimeIds = (pubTimeList.value || []).map(x => x.id);
/** 与智库报告一致:仅「全部时间」或选满所有具体年份 → 不按 years 狭义过滤 */
const isPolicyAllTime =
strippedPolicyYears.length === 0 ||
(allPubTimeIds.length > 0 && isSelectionCoveringAllOptions(strippedPolicyYears, allPubTimeIds));
const typeIdsForApi = stripAllAreaForRequest(policySelectedTypeIds.value);
// 领域:未选具体领域(仅「全部领域」)时传全量 id 串
const effectiveDomainIds = typeIdsForApi.length
? typeIdsForApi
: (areaList.value || []).map(obj => obj.id);
const effectiveDomainIds = typeIdsForApi.length ? typeIdsForApi : (areaList.value || []).map(obj => obj.id);
const domainIdsStr = arrayToString(effectiveDomainIds);
const params = {
currentPage: policyCurrentPage.value - 1,
......@@ -2000,7 +2243,7 @@ function arrayToString(arr) {
const handleGetetThinkTankReport = async () => {
const { startDate, endDate } = getResourceLibraryReportDateRangeFromTimeSelection(
stripAllTimeForRequest(selectedPubTimeList.value),
(pubTimeList.value || []).map((x) => x.id)
(pubTimeList.value || []).map(x => x.id)
);
const params = {
pageNum: currentPage.value,
......@@ -2008,7 +2251,7 @@ const handleGetetThinkTankReport = async () => {
sortFun: sort.value === true,
domainIds: (() => {
const areas = stripAllAreaForRequest(selectedAreaList.value);
const allAreaIds = (areaList.value || []).map((a) => a.id);
const allAreaIds = (areaList.value || []).map(a => a.id);
if (isSelectionCoveringAllOptions(areas, allAreaIds)) {
return "";
}
......@@ -2107,7 +2350,7 @@ const handleClickPerson = async item => {
ElMessage.warning("找不到当前人员的类型值!");
return;
}
} catch (error) { }
} catch (error) {}
};
// 点击新闻条目,跳转到新闻分析页
......@@ -2146,7 +2389,7 @@ const handleSearch = () => {
onMounted(async () => {
handleGetThinkTankList();
handleGetAllThinkTankList()
handleGetAllThinkTankList();
await getStatCountInfo();
// 定义一个定时器,每隔2秒轮播一次
setInterval(() => {
......@@ -2480,7 +2723,6 @@ onMounted(async () => {
cursor: pointer;
position: relative; // 让 red-info 按当前 card 自身定位
&:hover {
transform: translateY(-3px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
......@@ -2547,9 +2789,6 @@ onMounted(async () => {
color: rgb(5, 95, 194);
}
}
}
.card-title {
......@@ -2560,7 +2799,6 @@ onMounted(async () => {
justify-content: space-between;
.title-left {
height: 24px;
color: rgba(59, 65, 75, 1);
font-family: "Source Han Sans CN";
......@@ -2712,7 +2950,6 @@ onMounted(async () => {
}
.home-main-center {
.center-top {
height: 450px;
display: flex;
......@@ -2790,7 +3027,6 @@ onMounted(async () => {
align-items: center;
justify-content: center;
.title {
color: rgb(255, 255, 255);
font-family: "Source Han Sans CN";
......@@ -2801,7 +3037,6 @@ onMounted(async () => {
letter-spacing: 0;
width: 80px;
height: 26px;
}
}
}
......@@ -2884,7 +3119,6 @@ onMounted(async () => {
.name {
display: flex;
height: 24px;
margin-top: 22px;
justify-content: space-between;
......@@ -2894,7 +3128,6 @@ onMounted(async () => {
height: 24px;
width: 211px;
.logo {
width: 16px;
height: 16px;
......@@ -2902,11 +3135,9 @@ onMounted(async () => {
flex: 0 0 16px;
margin-right: 6px;
img {
width: 100%;
height: 100%;
}
}
......@@ -2921,9 +3152,6 @@ onMounted(async () => {
}
}
.time {
height: 24px;
color: rgb(59, 65, 75);
......@@ -2934,7 +3162,6 @@ onMounted(async () => {
letter-spacing: 0px;
text-align: left;
}
}
.content {
......@@ -2953,7 +3180,6 @@ onMounted(async () => {
font-weight: 400;
letter-spacing: 0px;
text-align: left;
}
}
}
......@@ -3472,7 +3698,6 @@ onMounted(async () => {
}
.center-footer {
height: 460px;
display: flex;
justify-content: center;
......@@ -3573,7 +3798,6 @@ onMounted(async () => {
}
.source {
position: absolute;
bottom: 21px;
left: 50%;
......@@ -3593,10 +3817,7 @@ onMounted(async () => {
img {
width: 100%;
height: 100%;
}
}
.text {
......@@ -3626,7 +3847,6 @@ onMounted(async () => {
position: absolute;
right: 0;
bottom: -18px;
}
}
}
......@@ -3680,7 +3900,7 @@ onMounted(async () => {
top: 12px;
right: 25px;
display: flex;
gap: 2px
gap: 2px;
}
}
......@@ -3713,7 +3933,6 @@ onMounted(async () => {
}
.source {
position: absolute;
bottom: 21px;
left: 50%;
......@@ -3734,10 +3953,7 @@ onMounted(async () => {
img {
width: 100%;
height: 100%;
}
}
.text {
......@@ -3767,12 +3983,9 @@ onMounted(async () => {
position: absolute;
right: 0;
bottom: -18px;
}
}
}
}
}
......@@ -3892,7 +4105,6 @@ onMounted(async () => {
}
.source {
position: absolute;
bottom: 21px;
left: 50%;
......@@ -3912,10 +4124,7 @@ onMounted(async () => {
img {
width: 100%;
height: 100%;
}
}
.text {
......@@ -3945,7 +4154,6 @@ onMounted(async () => {
position: absolute;
right: 0;
bottom: -18px;
}
}
}
......@@ -4006,7 +4214,6 @@ onMounted(async () => {
}
.box8-main {
height: 412px;
.box8-main-item {
......@@ -4055,7 +4262,7 @@ onMounted(async () => {
width: 92px;
text-align: right;
font-family: "Source Han Sans CN";
color: rgb(95, 101, 108)
color: rgb(95, 101, 108);
}
.itemBold1 {
......@@ -4107,7 +4314,6 @@ onMounted(async () => {
justify-content: space-between;
.btn-box {
display: flex;
gap: 24px;
......@@ -4381,8 +4587,6 @@ onMounted(async () => {
/* 仅作用于智库概览页资源库下四个组件的选择框样式 */
.resource-library-content {
:deep(.el-checkbox__label) {
font-family: "Source Han Sans CN";
font-size: 16px;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论