提交 d3315d67 authored 作者: 张烨's avatar 张烨

fix:科技政令-处理部分bug以及性能优化

上级 ba800b15
...@@ -265,12 +265,13 @@ const onHighlightedText = (text, nounList) => { ...@@ -265,12 +265,13 @@ const onHighlightedText = (text, nounList) => {
const key = `${searchInterval.start}-${searchInterval.end}`; const key = `${searchInterval.start}-${searchInterval.end}`;
if (end === searchInterval.end && !pointAdded.has(key)) { if (end === searchInterval.end && !pointAdded.has(key)) {
findWordMax.value++; findWordMax.value++;
list.push({ point: true, class: "" }); list.push({ point: findWordMax.value, class: "" });
pointAdded.add(key); pointAdded.add(key);
break; break;
} }
} }
} }
console.log('看看格式', list);
return list; return list;
}; };
......
...@@ -19,7 +19,7 @@ const decreeRoutes = [ ...@@ -19,7 +19,7 @@ const decreeRoutes = [
name: "Decree", name: "Decree",
component: Decree, component: Decree,
meta: { meta: {
title: "科技政令概", title: "科技政令概",
isShowHeader: true isShowHeader: true
} }
}, },
......
...@@ -6,19 +6,19 @@ ...@@ -6,19 +6,19 @@
<div class="hard-num text-title-2-show">{{ organizationInfo.total }}</div> <div class="hard-num text-title-2-show">{{ organizationInfo.total }}</div>
<div style="width: 0px; flex: auto;"></div> <div style="width: 0px; flex: auto;"></div>
<div class="hard-input"> <div class="hard-input">
<el-input v-model="organizationInfo.keyWord" @keyup.enter="onAllOrganization()" <el-input v-model="organizationInfo.keyWord" @keyup.enter="onAllOrganization()" @clear="onAllOrganization()"
style="width:100%; height:100%;" :suffix-icon="Search" placeholder="搜索机构" /> style="width:100%; height:100%;" :prefix-icon="Search" placeholder="搜索机构" clearable />
</div> </div>
<div class="hard-time"> <div class="hard-time">
<el-select v-model="organizationInfo.isSort" @change="onAllOrganization()" placeholder="发布时间" <el-select v-model="organizationInfo.isSort" @change="onAllOrganization()" style="width:100%;">
style="width:160px; margin-left:8px;">
<template #prefix> <template #prefix>
<div class="icon1"> <div class="icon1">
<img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" /> <img src="@/assets/icons/jiangxu1.png" alt="" />
<img v-else src="@/assets/icons/jiangxu1.png" alt="" /> <!-- <img src="@/assets/icons/shengxu1.png" alt="" /> -->
</div> </div>
</template> </template>
<el-option label="政令数量" :value="1" /> <el-option label="政令数据总量" :value="1" />
<el-option label="政令新增数量" :value="2" />
</el-select> </el-select>
</div> </div>
</div> </div>
...@@ -30,13 +30,12 @@ ...@@ -30,13 +30,12 @@
<TimeTabPane @time-click="handleDateChange" activeTime="近一年" /> <TimeTabPane @time-click="handleDateChange" activeTime="近一年" />
</div> </div>
<div class="organization-list" ref="refOrganization" v-loading="organizationInfo.loading"> <div class="organization-list" ref="refOrganization" v-loading="organizationInfo.loading">
<div class="organization-item" v-for="(item, index) in organizationInfo.list" :key="index" <div class="organization-item" v-for="item in organizationInfo.list" :key="item.orgId">
@click="handleToInstitution(item)">
<div class="item-left"> <div class="item-left">
<img :src="item.orgImage || DefaultIcon2" alt="" /> <img :src="item.orgImage || DefaultIcon2" alt="" />
</div> </div>
<div class="item-right one-line-ellipsis">{{ item.orgName }}</div> <div class="item-right one-line-ellipsis text-click-hover" @click="handleToInstitution(item)">{{ item.orgName }}</div>
<div class="item-total">{{ item.total }}项</div> <div class="item-total text-click-hover" @click="handleToDataLibrary(item)">{{ item.total }}项</div>
<el-icon color="var(--color-primary-100)"> <el-icon color="var(--color-primary-100)">
<ArrowRightBold /> <ArrowRightBold />
</el-icon> </el-icon>
...@@ -50,17 +49,15 @@ ...@@ -50,17 +49,15 @@
</div> </div>
</div> </div>
<div class="back-bnt" @click="router.back()"> <div class="back-bnt" @click="router.back()">
<el-icon> <el-icon> <Back /> </el-icon>
<Back />
</el-icon>
<div style="margin-left: 6px;">返回</div> <div style="margin-left: 6px;">返回</div>
</div> </div>
</div> </div>
</template> </template>
<script setup name="index"> <script setup>
import { onMounted, reactive, ref } from "vue" import { onMounted, reactive, ref } from "vue"
import { Search } from '@element-plus/icons-vue' import { Search, Back } from '@element-plus/icons-vue'
import router from "@/router"; import router from "@/router";
import TimeTabPane from '@/components/base/TimeTabPane/index.vue'; import TimeTabPane from '@/components/base/TimeTabPane/index.vue';
...@@ -112,9 +109,7 @@ const handleToInstitution = item => { ...@@ -112,9 +109,7 @@ const handleToInstitution = item => {
window.sessionStorage.setItem("curTabName", item.orgName); window.sessionStorage.setItem("curTabName", item.orgName);
const curRoute = router.resolve({ const curRoute = router.resolve({
path: "/institution", path: "/institution",
query: { query: { id: item.orgId }
id: item.orgId
}
}); });
window.open(curRoute.href, "_blank"); window.open(curRoute.href, "_blank");
// router.push({ // router.push({
...@@ -125,6 +120,15 @@ const handleToInstitution = item => { ...@@ -125,6 +120,15 @@ const handleToInstitution = item => {
// }) // })
}; };
// 下钻至数据资源库
const handleToDataLibrary = (item) => {
const route = router.resolve({
path: "/dataLibrary/dataDecree",
query: { orgnizationName: item.orgName }
});
window.open(route.href, "_blank");
}
const refOrganization = ref() const refOrganization = ref()
onMounted(() => { onMounted(() => {
// 根据元素的高度决定分页显示的机构数量 // 根据元素的高度决定分页显示的机构数量
...@@ -196,15 +200,14 @@ onMounted(() => { ...@@ -196,15 +200,14 @@ onMounted(() => {
background-color: var(--el-fill-color-blank); background-color: var(--el-fill-color-blank);
border-radius: var(--el-border-radius-base); border-radius: var(--el-border-radius-base);
box-shadow: 0 0 0 1px var(--el-border-color) inset; box-shadow: 0 0 0 1px var(--el-border-color) inset;
box-sizing: border-box;
margin-left: 20px;
width: 160px; width: 160px;
height: 32px; height: 32px;
} }
.hard-time { .hard-time {
height: 42px; height: 32px;
padding: 5px 0; width: 160px;
margin-left: 8px;
.icon1 { .icon1 {
width: 11px; width: 11px;
...@@ -269,7 +272,6 @@ onMounted(() => { ...@@ -269,7 +272,6 @@ onMounted(() => {
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
align-items: center; align-items: center;
justify-content: 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; position: relative;
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
<div class="center-top"> <div class="center-top">
<OverviewMainBox class="box1" title="最新科技政令" @toDetail="handleClickOrder"> <OverviewMainBox class="box1" title="最新科技政令" @toDetail="handleClickOrder">
<template #header-icon> <template #header-icon>
<img style="width: 100%; height: 100%" src="./assets/images/box1-header-icon.png" alt="" /> <img style="width: 100%; height: 100%" src="./assets/images/icon_1596.png" alt="" />
</template> </template>
<div class="box1-left" @click="handleSwithCurDecree('left')"> <div class="box1-left" @click="handleSwithCurDecree('left')">
<div class="icon"> <div class="icon">
...@@ -77,25 +77,20 @@ ...@@ -77,25 +77,20 @@
</div> </div>
</div> </div>
<div class="box1-main-right"> <div class="box1-main-right">
<div class="box1-main-right-title"> <div class="box1-main-right-title">{{ item.name }}</div>
{{ item.name }} <div class="box1-main-right-info" v-if="item.industryList?.length">
</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>
<div class="box1-main-right-center"> <div class="box1-main-right-center">{{ item.describe }}</div>
{{ item.describe }} <div style="height: 0; flex: auto;"></div>
</div>
<div class="box1-main-right-footer"> <div class="box1-main-right-footer">
<div class="footer-left">{{ item.postDate }}</div> <div class="footer-left">{{ item.postDate }}</div>
<div class="footer-right"> <!-- <div class="footer-right">
<div class="footer-right-item1"> <div class="footer-right-item1">{{ item.officialUrl }}</div>
{{ item.officialUrl }}
</div>
<div class="footer-right-item2"> <div class="footer-right-item2">
<img src="./assets/images/open-icon.png" alt="" /> <img src="./assets/images/open-icon.png" alt="" />
</div> </div>
</div> </div> -->
</div> </div>
</div> </div>
</div> </div>
...@@ -114,77 +109,66 @@ ...@@ -114,77 +109,66 @@
</div> </div>
<DivideHeader id="position3" class="divide3" :titleText="'数据总览'"></DivideHeader> <DivideHeader id="position3" class="divide3" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer"> <div class="center-footer">
<div class="box5"> <div class="box5" v-loading="box5Params.loading">
<div class="box5-header"> <div class="box5-header">
<div class="box5-header-icon"> <div class="box5-header-icon">
<img src="./assets/images/box3-header-icon.png" alt="" /> <img src="./assets/images/box3-header-icon.png" alt="" />
</div> </div>
<div class="box5-header-title">{{ "数量变化趋势" }}</div> <div class="box5-header-title">{{ "数量变化趋势" }}</div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleBox5" v-model="box5Params.proposeName" :empty-values="[null, undefined]" <el-select @change="getBox5Data" v-model="box5Params.proposeName" :empty-values="[null, undefined]" style="width:150px" filterable>
style="width:150px">
<el-option label="全部政府部门" value="" /> <el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" <el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
:value="item.orgId" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleBox5" v-model="box5Params.domainId" :empty-values="[null, undefined]" <el-select @change="getBox5Data" v-model="box5Params.domainId" :empty-values="[null, undefined]" style="width:120px">
style="width:120px">
<el-option label="全部领域" value="" /> <el-option label="全部领域" value="" />
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleBox5" v-model="box5Params.year" placeholder="选择时间" style="width:120px"> <el-select @change="getBox5Data" 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-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="box5-main" v-loading="box5Params.loading"> <div class="box5-main" style="padding-top: 16px;">
<div class="box5-chart" id="chart1"></div> <div v-if="chart1Data.dataX?.length" class="box5-chart" id="chart1"></div>
<el-empty v-else style="padding-top: 100px;" description="暂无数据" :image-size="100" />
</div> </div>
<div class="data-origin-box"> <div style="padding: 14px 22px;">
<div class="data-origin-icon"> <TipTab text="数据来源:美国各行政机构官网" />
<img :src="tipsTcon" alt="">
</div>
<div class="data-origin-text">科技政令数量变化趋势,数据来源:美国各行政机构官网</div>
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
<AiPane :aiContent="aiContent.content1" /> <AiPane :aiContent="aiContent.content1" />
</div> </div>
</div> </div>
<div class="box5" v-loading="box6Params.loading">
<div class="box5">
<div class="box5-header"> <div class="box5-header">
<div class="box5-header-icon"> <div class="box5-header-icon">
<img src="./assets/images/box4-header-icon.png" alt="" /> <img src="./assets/images/box4-header-icon.png" alt="" />
</div> </div>
<div class="box5-header-title">{{ "领域分布情况" }}</div> <div class="box5-header-title">{{ "领域分布情况" }}</div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleBox6YearChange" v-model="box6Params.proposeName" <el-select @change="getBox6Data" v-model="box6Params.proposeName" :empty-values="[null, undefined]" style="width:150px" filterable>
:empty-values="[null, undefined]" style="width:150px">
<el-option label="全部政府部门" value="" /> <el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" <el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
:value="item.orgId" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleBox6YearChange" v-model="box6Params.year" placeholder="选择时间" <el-select @change="getBox6Data" v-model="box6Params.year" placeholder="选择时间" style="width: 120px">
style="width: 120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="box5-main" v-loading="box6Params.loading"> <div class="box5-main" style="padding: 16px 22px 0;">
<div class="box5-chart" id="chart2"></div> <div v-if="chart2Data.length" class="box5-chart" ref="box6Ref"></div>
</div> <el-empty v-else style="padding-top: 100px;" description="暂无数据" :image-size="100" />
<div class="data-origin-box">
<div class="data-origin-icon">
<img :src="tipsTcon" alt="">
</div> </div>
<div class="data-origin-text">科技政令领域分布情况,数据来源:美国各行政机构官网</div> <div style="padding: 14px 22px;">
<TipTab text="数据来源:美国各行政机构官网" />
</div> </div>
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
...@@ -193,121 +177,111 @@ ...@@ -193,121 +177,111 @@
</div> </div>
</div> </div>
<div class="center-footer1"> <div class="center-footer1">
<div class="box7"> <div class="box7" v-loading="box7Params.loading">
<div class="box7-header"> <div class="box7-header">
<div class="header-icon"> <div class="header-icon">
<img src="./assets/images/box5-header-icon.png" alt="" /> <img src="./assets/images/box5-header-icon.png" alt="" />
</div> </div>
<div class="header-title">{{ "关键科技政令" }}</div> <div class="header-title">{{ "关键科技政令" }}</div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleGetKeyDecree" v-model="box7Params.proposeName" <el-select @change="getBox7Data(1)" v-model="box7Params.proposeName" :empty-values="[null, undefined]" style="width:150px" filterable>
:empty-values="[null, undefined]" style="width:150px">
<el-option label="全部政府部门" value="" /> <el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" <el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
:value="item.orgId" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleGetKeyDecree" v-model="box7Params.domainId" :empty-values="[null, undefined]" <el-select @change="getBox7Data(1)" v-model="box7Params.domainId" :empty-values="[null, undefined]" style="width:120px">
style="width:120px">
<el-option label="全部领域" value="" /> <el-option label="全部领域" value="" />
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleGetKeyDecree" v-model="box7Params.year" placeholder="选择时间" <el-select @change="getBox7Data(1)" v-model="box7Params.year" placeholder="选择时间" style="width:120px">
style="width:120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="box7-main" v-loading="box7Params.loading"> <div class="box7-main">
<div class="box7-list"> <div v-if="keyDecreeList?.length" class="box7-list">
<div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index" <div class="box7-item" v-for="(item, index) in keyDecreeList" :key="index" @click="onNavigateToDetail(item)">
@click="onNavigateToDetail(item)">
<div class="icon"> <div class="icon">
<img src="./assets/images/warning.png" alt="" /> <img src="./assets/images/warning.png" alt="" />
</div> </div>
<div class="info"> <div class="info">
<div class="info-header"> <div class="info-header">
<div class="title one-line-ellipsis">{{ item.title }}</div> <div class="title one-line-ellipsis">{{ item.name }}</div>
<div class="time">{{ item.time }}</div> <div class="time">{{ item.postDate }}</div>
</div> </div>
<div class="info-content one-line-ellipsis">{{ item.content || "暂无数据" }}</div> <div class="info-content one-line-ellipsis">{{ item.describe || "暂无数据" }}</div>
</div> </div>
</div> </div>
</div> </div>
<el-empty v-else style="padding-top: 100px;" description="暂无数据" :image-size="100" />
</div> </div>
<SimplePagination v-model:current-page="keyDecreeInfo.page" :page-size="keyDecreeInfo.size" <SimplePagination v-if="keyDecreeList?.length" v-model:current-page="keyDecreeInfo.page" :page-size="keyDecreeInfo.size" :total="keyDecreeInfo.total" @page-change="getBox7Data" />
:total="keyDecreeInfo.total" @page-change="handleGetKeyDecree" /> <div style="padding: 14px 22px;">
<div class="data-origin-box"> <TipTab text="数据来源:美国各行政机构官网" />
<div class="data-origin-icon">
<img :src="tipsTcon" alt="">
</div> </div>
<div class="data-origin-text">关键科技政令列表,数据来源:美国各行政机构官网</div>
</div> </div>
</div> <div class="box8" v-loading="box8Params.loading">
<div class="box8">
<div class="box8-header"> <div class="box8-header">
<div class="header-icon"> <div class="header-icon">
<img src="./assets/images/box5-header-icon.png" alt="" /> <img src="./assets/images/box5-header-icon.png" alt="" />
</div> </div>
<div class="header-title">{{ "关键条款词云" }}</div> <div class="header-title">{{ "关键条款词云" }}</div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleGetDecreeKeyInstruction" v-model="box8Params.proposeName" <el-select @change="getBox8Data" v-model="box8Params.proposeName" :empty-values="[null, undefined]" style="width:150px" filterable>
:empty-values="[null, undefined]" style="width:150px">
<el-option label="全部政府部门" value="" /> <el-option label="全部政府部门" value="" />
<el-option v-for="item in keyOrganizationList" :key="item.orgId" :label="item.orgName" <el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
:value="item.orgId" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleGetDecreeKeyInstruction" v-model="box8Params.domainId" <el-select @change="getBox8Data" v-model="box8Params.domainId" :empty-values="[null, undefined]" style="width:120px">
:empty-values="[null, undefined]" style="width:120px">
<el-option label="全部领域" value="" /> <el-option label="全部领域" value="" />
<el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in areaList" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</div> </div>
<div style="margin-right: 20px;"> <div style="margin-right: 20px;">
<el-select @change="handleGetDecreeKeyInstruction" v-model="box8Params.year" placeholder="选择时间" <el-select @change="getBox8Data" v-model="box8Params.year" placeholder="选择时间" style="width:120px">
style="width:120px">
<el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in yearList" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</div> </div>
</div> </div>
<div class="box8-content" v-loading="box8Params.loading"> <div class="box8-content">
<WordCloudChart v-if="wordCloudData?.length" :data="wordCloudData" width="100%" height="100%" /> <WordCloudChart v-if="wordCloudData?.length" :data="wordCloudData" width="100%" height="100%" />
<el-empty v-else style="padding-top: 100px;" description="暂无数据" :image-size="100" />
</div> </div>
<div class="data-origin-box"> <div style="padding: 14px 22px;">
<div class="data-origin-icon"> <TipTab text="数据来源:美国各行政机构官网" />
<img :src="tipsTcon" alt="">
</div> </div>
<div class="data-origin-text">科技政令重点条款词云,数据来源:美国各行政机构官网</div> <div class="ai-pane">
<AiButton />
<AiPane :aiContent="aiContent.content3" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="home-main-footer"> <div class="home-main-footer">
<DivideHeader id="position4" class="divide4" :titleText="'科技政令库'"></DivideHeader> <DivideHeader id="position4" class="divide4" :titleText="'科技政令数据库'"></DivideHeader>
<div class="home-main-footer-header"> <div class="home-main-footer-head">
<div class="search-box"> <div class="search-box">
<el-select v-model="searchType" :empty-values="[null, undefined]" style="width: 100%" filterable> <el-select v-model="box9Params.name" :empty-values="[null, undefined]" @change="getDecreeList(1)" style="width: 100%" filterable>
<el-option label="全部政府部门" value="" /> <el-option label="全部政府部门" value="" />
<el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" /> <el-option v-for="item in govInsList" :key="item.orgId" :label="item.orgName" :value="item.orgId" />
</el-select> </el-select>
</div> </div>
<div style="flex: auto;"></div> <div style="flex: auto;"></div>
<el-checkbox v-model="isChina">只看涉华政令</el-checkbox> <el-checkbox @change="getDecreeList(1)" v-model="box9Params.isCN">只看涉华政令</el-checkbox>
<div class="select-box"> <div class="select-box">
<el-select v-model="isSort" placeholder="发布时间" style="width:120px; margin-left:8px;"> <el-select v-model="box9Params.sortFun" @change="getDecreeList(1)" style="width:166px; margin-left:8px;">
<template #prefix> <template #prefix>
<div class="icon1"> <div class="icon1">
<img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" /> <img v-if="box9Params.sortFun=='1'" src="@/assets/icons/shengxu1.png" alt="" />
<img v-else src="@/assets/icons/jiangxu1.png" alt="" /> <img v-else src="@/assets/icons/jiangxu1.png" alt="" />
</div> </div>
</template> </template>
<el-option label="正序" :value="true" /> <el-option label="发布时间正序" value="1" />
<el-option label="倒序" :value="false" /> <el-option label="发布时间倒序" value="0" />
</el-select> </el-select>
</div> </div>
</div> </div>
...@@ -319,13 +293,12 @@ ...@@ -319,13 +293,12 @@
<div class="title">{{ "政令类型" }}</div> <div class="title">{{ "政令类型" }}</div>
</div> </div>
<div class="select-main"> <div class="select-main">
<div class="checkbox-group"> <el-checkbox-group class="checkbox-group" v-model="checkedDecreeType" @change="handleTypeChange">
<el-checkbox v-for="type in decreeTypeList" :key="type.id" v-model="checkedDecreeType" <el-checkbox label="" class="filter-checkbox">{{ "全部类型" }}</el-checkbox>
:label="type.typeId" style="width: 180px" class="filter-checkbox" <el-checkbox v-for="item in decreeTypeList" :key="item.typeId" :label="item.typeId" class="filter-checkbox">
@change="handleChangeCheckedDecreeType"> {{ item.typeName }}
{{ type.typeName }}
</el-checkbox> </el-checkbox>
</div> </el-checkbox-group>
</div> </div>
</div> </div>
<div class="select-box"> <div class="select-box">
...@@ -349,6 +322,7 @@ ...@@ -349,6 +322,7 @@
</div> </div>
<div class="select-main"> <div class="select-main">
<el-checkbox-group class="checkbox-group" v-model="activePubTime" @change="handlePubTimeChange"> <el-checkbox-group class="checkbox-group" v-model="activePubTime" @change="handlePubTimeChange">
<el-checkbox label="" class="filter-checkbox">{{ "全部时间" }}</el-checkbox>
<el-checkbox v-for="time in pubTime" :key="time.id" :label="time.id" class="filter-checkbox"> <el-checkbox v-for="time in pubTime" :key="time.id" :label="time.id" class="filter-checkbox">
{{ time.name }} {{ time.name }}
</el-checkbox> </el-checkbox>
...@@ -356,36 +330,36 @@ ...@@ -356,36 +330,36 @@
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <div class="right" v-loading="box9Params.loading">
<div class="content-header"> <div class="content-header">
<div class="icon"> <div class="icon">
<img src="./assets/images/footer-header-icon.png" alt="" /> <img src="./assets/images/footer-header-icon.png" alt="" />
</div> </div>
<div class="title">{{ "政令库" }}</div> <div class="title">{{ "政令库" }}</div>
</div> </div>
<div class="content-box" v-show="decreeList"> <div class="content-box">
<el-empty v-if="!decreeList.length" style="padding-top: 160px;" description="暂无数据" :image-size="100" />
<div class="main-item" v-for="(item, index) in decreeList" :key="index" @click="onNavigateToDetail(item)"> <div class="main-item" v-for="(item, index) in decreeList" :key="index" @click="onNavigateToDetail(item)">
<div class="main-item-left"> <div class="main-item-left">
<div class="left-left"> <div class="left-left">
{{ item.time?.split("-")[0] }}<br />{{ item.time?.split("-")[1] }}月{{ {{ item.postDate?.split("-")[0] }}<br />
item.time?.split("-")[2] {{ item.postDate?.split("-")[1] }}月{{ item.postDate?.split("-")[2] }}日
}}日
</div> </div>
<div class="left-right"> <div class="left-right">
<div class="icon"> <div class="icon">
<img :src="item.img ? item.img : DefaultIcon2" alt="" /> <img :src="item.orgImage || DefaultIcon2" alt="" />
</div> </div>
<div class="line" v-if="index !== 9 && index !== totalDecreesNum - 1"></div> <div class="line" v-if="index !== 9 && index !== totalDecreesNum - 1"></div>
</div> </div>
</div> </div>
<div class="main-item-center"> <div class="main-item-center">
<div class="center-header"> <div class="center-header">
<div class="title">{{ item.title }}</div> <div class="title one-line-ellipsis">{{ `${item.proposeOrgName}: ${item.name}` }}</div>
<!-- <div class="type-box type1">{{ item.type }}</div> --> <div class="type-box type1">{{ '行政命令' }}</div>
</div> </div>
<div class="desc">{{ item.desc }}</div> <div class="desc">{{ item.describe }}</div>
<div class="tag-box"> <div class="tag-box">
<AreaTag v-for="(tag, index) in item.tagList" :key="index" :tagName="tag.industryName" /> <AreaTag v-for="(tag, index) in item.industryList" :key="index" :tagName="tag.industryName" />
</div> </div>
</div> </div>
</div> </div>
...@@ -395,7 +369,7 @@ ...@@ -395,7 +369,7 @@
{{ `共 ${totalDecreesNum} 项` }} {{ `共 ${totalDecreesNum} 项` }}
</div> </div>
<div class="footer-right"> <div class="footer-right">
<el-pagination @current-change="handleCurrentChange" :pageSize="10" :current-page="currentPage" <el-pagination @current-change="handleCurrentChange" :pageSize="box9Params.size" :current-page="box9Params.page"
background layout="prev, pager, next" :total="totalDecreesNum" /> background layout="prev, pager, next" :total="totalDecreesNum" />
</div> </div>
</div> </div>
...@@ -414,7 +388,7 @@ ...@@ -414,7 +388,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, watch, nextTick, reactive, computed } from "vue"; import { onMounted, ref, nextTick, reactive, computed } from "vue";
import router from "@/router"; import router from "@/router";
import { navigateToViewRiskSignal } from "@/utils/riskSignalOverviewNavigate"; import { navigateToViewRiskSignal } from "@/utils/riskSignalOverviewNavigate";
import RiskSignalOverviewDetailDialog from "@/components/base/RiskSignalOverviewDetailDialog/index.vue"; import RiskSignalOverviewDetailDialog from "@/components/base/RiskSignalOverviewDetailDialog/index.vue";
...@@ -423,6 +397,7 @@ import SimplePagination from "@/components/SimplePagination.vue"; ...@@ -423,6 +397,7 @@ import SimplePagination from "@/components/SimplePagination.vue";
import SummaryCardsPanel from "@/components/base/SummaryCardsPanel/index.vue"; import SummaryCardsPanel from "@/components/base/SummaryCardsPanel/index.vue";
import AiButton from '@/components/base/Ai/AiButton/index.vue'; import AiButton from '@/components/base/Ai/AiButton/index.vue';
import AiPane from '@/components/base/Ai/AiPane/index.vue'; import AiPane from '@/components/base/Ai/AiPane/index.vue';
import TipTab from "@/components/base/TipTab/index.vue"
import { import {
getDepartmentList, getDepartmentList,
getLatestDecree, getLatestDecree,
...@@ -441,8 +416,7 @@ import { getNews, getSocialMedia } from "@/api/general/index"; ...@@ -441,8 +416,7 @@ import { getNews, getSocialMedia } from "@/api/general/index";
import DivideHeader from "@/components/DivideHeader.vue"; import DivideHeader from "@/components/DivideHeader.vue";
import { useContainerScroll } from "@/hooks/useScrollShow"; import { useContainerScroll } from "@/hooks/useScrollShow";
import getBarChart from "./utils/barChart"; import getBarChart from "./utils/barChart";
import getPieChart from "./utils/piechart"; import createPieChart from "@/views/marketAccessRestrictions/utils/basePiechart.js";
import setChart from "@/utils/setChart"; import setChart from "@/utils/setChart";
import DefaultIcon2 from "@/assets/icons/default-icon2.png"; import DefaultIcon2 from "@/assets/icons/default-icon2.png";
...@@ -454,18 +428,14 @@ import { useGotoNewsDetail } from '@/router/modules/news'; ...@@ -454,18 +428,14 @@ import { useGotoNewsDetail } from '@/router/modules/news';
const containerRef = ref(null); const containerRef = ref(null);
const { isShow } = useContainerScroll(containerRef); const { isShow } = useContainerScroll(containerRef);
const currentPage = ref(1);
const pageSize = ref(10);
// 处理页码改变事件 // 处理页码改变事件
const handleCurrentChange = page => { const handleCurrentChange = page => {
currentPage.value = page;
handleToPosi('position4') handleToPosi('position4')
handleGetDecreeOrderList(); getDecreeList(page);
}; };
// 机构列表 // 机构列表
const govInsList = ref([]); const govInsList = ref([]);
const checkedGovIns = ref([]);
const handleGetDepartmentList = async () => { const handleGetDepartmentList = async () => {
try { try {
const res = await getDepartmentList({}); const res = await getDepartmentList({});
...@@ -473,9 +443,7 @@ const handleGetDepartmentList = async () => { ...@@ -473,9 +443,7 @@ const handleGetDepartmentList = async () => {
if (res.code === 200) { if (res.code === 200) {
govInsList.value = res.data.orgList; govInsList.value = res.data.orgList;
} }
} catch (error) { } catch (error) {}
console.error("获取机构列表error", error);
}
}; };
// 跳转行政机构主页 // 跳转行政机构主页
const handleToInstitution = item => { const handleToInstitution = item => {
...@@ -540,9 +508,7 @@ const handleGetLatestDecree = async () => { ...@@ -540,9 +508,7 @@ const handleGetLatestDecree = async () => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
box1DataList.value = res.data; box1DataList.value = res.data;
} }
} catch (error) { } catch (error) {}
console.error("最新科技政令error", error);
}
}; };
const handleBox1 = async () => { const handleBox1 = async () => {
...@@ -588,9 +554,7 @@ const handlegetDecreeRiskSignal = async () => { ...@@ -588,9 +554,7 @@ const handlegetDecreeRiskSignal = async () => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
warningList.value = res.data.map(item => ({ ...item, id: item.orderId })); warningList.value = res.data.map(item => ({ ...item, id: item.orderId }));
} }
} catch (error) { } catch (error) {}
console.error("风险信号error", error);
}
}; };
handlegetDecreeRiskSignal(); handlegetDecreeRiskSignal();
...@@ -624,9 +588,7 @@ const handleGetNews = async () => { ...@@ -624,9 +588,7 @@ const handleGetNews = async () => {
}; };
}); });
} }
} catch (error) { } catch (error) {}
console.error("新闻资讯error", error);
}
}; };
// 点击新闻条目,跳转到新闻分析页 // 点击新闻条目,跳转到新闻分析页
const gotoNewsDetail = useGotoNewsDetail() const gotoNewsDetail = useGotoNewsDetail()
...@@ -738,13 +700,14 @@ const yearList = getNearYearList(); ...@@ -738,13 +700,14 @@ const yearList = getNearYearList();
const aiContent = reactive({ const aiContent = reactive({
content1: "正在生成...", content1: "正在生成...",
content2: "正在生成...", content2: "正在生成...",
content3: "正在生成...",
}) })
const onAIReport = (data, key) => { const onAIReport = (data, key) => {
getAIReport(data).then(res => { aiContent[key] = res }) getAIReport(data).then(res => { aiContent[key] = res })
} }
// 行政令发布频度 // 数量变化趋势
const chart1Data = ref({ const chart1Data = reactive({
dataX: [], dataX: [],
dataY: [] dataY: []
}); });
...@@ -757,121 +720,88 @@ const box5Params = reactive({ ...@@ -757,121 +720,88 @@ const box5Params = reactive({
const handleGetDecreeYearOrder = async () => { const handleGetDecreeYearOrder = async () => {
box5Params.loading = true box5Params.loading = true
try { try {
let { year, domainId, proposeName } = box5Params;
const res = await getDecreeYearOrder({ const res = await getDecreeYearOrder({
year, year: box5Params.year,
domainId: domainId || undefined, domainId: box5Params.domainId || null,
orgId: proposeName || undefined orgId: box5Params.proposeName || null
}); });
console.log("行政令发布频度", res); console.log("数量变化趋势", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
chart1Data.value.dataX = res.data.map(item => { chart1Data.dataX = res.data.map(item => item.year);
return item.year; chart1Data.dataY = res.data.map(item => item.count);
}); onAIReport({ type: "柱状图", name: "数量变化趋势", data: chart1Data }, "content1")
chart1Data.value.dataY = res.data.map(item => {
return item.count;
});
onAIReport({ type: "柱状图", name: "数量变化趋势", data: res.data }, "content1")
} else { } else {
chart1Data.value.dataX = []; chart1Data.dataX = [];
chart1Data.value.dataY = []; chart1Data.dataY = [];
aiContent.content1 = "" aiContent.content1 = "数据为空"
} }
} catch (error) { } catch (error) {
console.error("行政令发布频度error", error); chart1Data.dataX = [];
chart1Data.dataY = [];
aiContent.content1 = "数据为空"
} }
box5Params.loading = false box5Params.loading = false
}; };
const getBox5Data = async () => {
const handleBox5 = async () => {
await handleGetDecreeYearOrder(); await handleGetDecreeYearOrder();
let chart1 = getBarChart(chart1Data.value.dataX, chart1Data.value.dataY); let chart1 = getBarChart(chart1Data.dataX, chart1Data.dataY);
chart1.yAxis.name = "数量"; chart1.yAxis.name = "数量";
chart1.yAxis.nameTextStyle = { align: 'right' } chart1.yAxis.nameTextStyle = { align: 'right' }
let org = '全部机构' let org = govInsList.value.find(item => item.orgId === box5Params.proposeName)?.orgName || '全部机构'
if (box5Params.proposeName) { let domain = areaList.value.find(item => item.id === box5Params.domainId)?.name || '全部领域'
org = keyOrganizationList.value.filter(item => { nextTick(() => {
return item.orgId === box5Params.proposeName setChart(chart1, "chart1", true, {
})[0].orgName
}
let domain = '全部领域'
if (box5Params.domainId) {
domain = areaList.value.filter(item => {
return item.id === box5Params.domainId
})[0].name
}
const selectParam = {
moduleType: '政令', moduleType: '政令',
orgnizationName: org, orgnizationName: org,
domains: domain, domains: domain,
selectDate: box5Params.year selectDate: box5Params.year
} })
setChart(chart1, "chart1", true, selectParam); })
}; };
// 政令科技领域 // 领域分布情况
const chart2Data = ref([ const chart2Data = ref([]);
// {
// name: "集成电路",
// value: 50
// },
// {
// name: "人工智能",
// value: 46
// },
]);
// const colorList = ["#69B1FF", "#FFC069", "#87E8DE", "#85A5FF", "#FF7875", "#B37FEB", "#4096FF"];
const box6Params = reactive({ const box6Params = reactive({
year: yearList[0].value, year: yearList[0].value,
proposeName: '', proposeName: '',
loading: false, loading: false,
}); });
const handleGetDecreeArea = async () => { const box6Ref = ref(null);
const getBox6Data = async () => {
box6Params.loading = true box6Params.loading = true
try { try {
let { year, proposeName } = box6Params;
const res = await getDecreeArea({ const res = await getDecreeArea({
year, year: box6Params.year,
orgId: proposeName || undefined orgId: box6Params.proposeName || null
}); });
console.log("政令科技领域", res); console.log("领域分布情况", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
chart2Data.value = res.data.map(item => { chart2Data.value = res.data.map(item => ({name: item.industry, value: item.count}));
return { onAIReport({ type: "环形图", name: "领域分布情况", data: chart2Data.value }, "content2")
name: item.industry,
value: item.count
};
});
onAIReport({ type: "环形图", name: "领域分布情况", data: res.data }, "content2")
} else { } else {
chart2Data.value = [] chart2Data.value = []
aiContent.content2 = "" aiContent.content2 = "数据为空"
} }
} catch (error) { } catch (error) {
console.error("政令科技领域error", error); chart2Data.value = []
aiContent.content2 = "数据为空"
} }
box6Params.loading = false box6Params.loading = false
}; nextTick(() => {
const handleBox6 = async () => { let box6Chart = createPieChart(box6Ref, chart2Data.value)
await handleGetDecreeArea(); box6Chart.on('click', (node) => {
let org = '全部机构' const route = router.resolve({
if (box6Params.proposeName) { path: "/dataLibrary/dataDecree",
org = keyOrganizationList.value.filter(item => { query: {
return item.orgId === box6Params.proposeName
})[0].orgName
}
const selectParam = {
moduleType: '政令', moduleType: '政令',
orgnizationName: org, orgnizationName: govInsList.value.find(item => item.orgId === box6Params.proposeName)?.orgName || '全部机构',
selectedDate: JSON.stringify([box6Params.year + '-01-01', box6Params.year + '-12-31']) domains: node.name,
selectedDate: JSON.stringify([`${box6Params.year}-01-01`, `${box6Params.year}-12-31`])
} }
let chart2 = getPieChart(chart2Data.value); });
setChart(chart2, "chart2", true, selectParam); window.open(route.href, "_blank");
}; })
})
const handleBox6YearChange = () => {
handleBox6();
}; };
// 关键行政令 // 关键行政令
...@@ -887,7 +817,8 @@ const box7Params = reactive({ ...@@ -887,7 +817,8 @@ const box7Params = reactive({
proposeName: '', proposeName: '',
loading: false, loading: false,
}) })
const handleGetKeyDecree = async () => { const getBox7Data = async (page) => {
if (page) keyDecreeInfo.page = page
box7Params.loading = true box7Params.loading = true
try { try {
let { year, domainId, proposeName } = box7Params; let { year, domainId, proposeName } = box7Params;
...@@ -899,22 +830,21 @@ const handleGetKeyDecree = async () => { ...@@ -899,22 +830,21 @@ const handleGetKeyDecree = async () => {
orgId: proposeName || undefined orgId: proposeName || undefined
}); });
console.log("关键行政令", res); console.log("关键行政令", res);
if (res.code === 200 && res.data?.total) { if (res.code === 200 && res.data.list) {
keyDecreeInfo.total = res.data.total || 0; keyDecreeInfo.total = res.data.total || 0;
keyDecreeList.value = res.data.list.map(item => { keyDecreeList.value = res.data.list;
return { } else {
title: item.name, keyDecreeInfo.total = 0
content: item.describe, keyDecreeList.value = []
time: item.postDate, }
id: item.orderId } catch (error) {
}; keyDecreeInfo.total = 0
}); keyDecreeList.value = []
} }
} catch (error) { }
box7Params.loading = false box7Params.loading = false
}; };
// 政令重点条款 // 关键条款词云
const wordCloudData = ref([]); const wordCloudData = ref([]);
const box8Params = reactive({ const box8Params = reactive({
year: yearList[0].value, year: yearList[0].value,
...@@ -922,7 +852,7 @@ const box8Params = reactive({ ...@@ -922,7 +852,7 @@ const box8Params = reactive({
proposeName: '', proposeName: '',
loading: false, loading: false,
}) })
const handleGetDecreeKeyInstruction = async () => { const getBox8Data = async () => {
box8Params.loading = true box8Params.loading = true
wordCloudData.value = [] wordCloudData.value = []
try { try {
...@@ -932,24 +862,21 @@ const handleGetDecreeKeyInstruction = async () => { ...@@ -932,24 +862,21 @@ const handleGetDecreeKeyInstruction = async () => {
domainId: domainId || undefined, domainId: domainId || undefined,
orgId: proposeName || undefined orgId: proposeName || undefined
}); });
console.log("政令重点条款", res); console.log("关键条款词云", res);
if (res.code == 200) { if (res.code == 200) {
wordCloudData.value = res.data.map(item => ({ name: item.clause, value: item.count })); wordCloudData.value = res.data.map(item => ({ name: item.clause, value: item.count }));
onAIReport({ type: "词云图", name: "关键条款词云", data: wordCloudData.value }, "content3")
} else { } else {
wordCloudData.value = [] wordCloudData.value = []
aiContent.content1 = "数据为空"
} }
} catch (error) { } catch (error) {
wordCloudData.value = [] wordCloudData.value = []
console.error("政令重点条款error", error); aiContent.content1 = "数据为空"
} }
box8Params.loading = false box8Params.loading = false
}; };
// 资源库
const searchType = ref("");
const isChina = ref(false);
const isSort = ref(false); // true 升序 false 降序
const handleToPosi = id => { const handleToPosi = id => {
const element = document.getElementById(id); const element = document.getElementById(id);
if (element && containerRef.value) { if (element && containerRef.value) {
...@@ -975,8 +902,7 @@ const handleToPosi = id => { ...@@ -975,8 +902,7 @@ const handleToPosi = id => {
// 政令类型 // 政令类型
const decreeTypeList = ref([]); const decreeTypeList = ref([]);
const checkedDecreeType = ref([]); const checkedDecreeType = ref(['']);
const handleGetDecreeTypeList = async () => { const handleGetDecreeTypeList = async () => {
try { try {
const res = await getDecreeTypeList(); const res = await getDecreeTypeList();
...@@ -984,8 +910,17 @@ const handleGetDecreeTypeList = async () => { ...@@ -984,8 +910,17 @@ const handleGetDecreeTypeList = async () => {
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
decreeTypeList.value = res.data; decreeTypeList.value = res.data;
} }
} catch (error) { } } catch (error) {}
}; };
const handleTypeChange = async (event) => {
if (event.length && event[event.length-1] !== "") {
checkedDecreeType.value = event.filter(item => item !== "");
} else {
checkedDecreeType.value = [""];
}
getDecreeList(1);
}
// 查看社交媒体详情 // 查看社交媒体详情
const handleToSocialDetail = item => { const handleToSocialDetail = item => {
const route = router.resolve({ const route = router.resolve({
...@@ -996,12 +931,8 @@ const handleToSocialDetail = item => { ...@@ -996,12 +931,8 @@ const handleToSocialDetail = item => {
}); });
window.open(route.href, "_blank"); window.open(route.href, "_blank");
}; };
const handleChangeCheckedDecreeType = () => {
handleGetDecreeOrderList();
};
const pubTime = ref([ const pubTime = ref([
{ id: "", name: "全部时间" },
{ id: "2026", name: "2026年" }, { id: "2026", name: "2026年" },
{ id: "2025", name: "2025年" }, { id: "2025", name: "2025年" },
{ id: "2024", name: "2024年" }, { id: "2024", name: "2024年" },
...@@ -1018,8 +949,7 @@ const handlePubTimeChange = (event) => { ...@@ -1018,8 +949,7 @@ const handlePubTimeChange = (event) => {
} else { } else {
activePubTime.value = [""]; activePubTime.value = [""];
} }
currentPage.value = 1; getDecreeList(1);
handleGetDecreeOrderList();
}; };
const activeAreaList = ref([""]); const activeAreaList = ref([""]);
...@@ -1029,18 +959,10 @@ const handleAreaChange = (event) => { ...@@ -1029,18 +959,10 @@ const handleAreaChange = (event) => {
} else { } else {
activeAreaList.value = [""]; activeAreaList.value = [""];
} }
getDecreeList(1);
currentPage.value = 1;
handleGetDecreeOrderList();
}; };
const areaList = ref([ const areaList = ref([]);
// { id: "人工智能", name: "人工智能" },
// { id: "集成电路", name: "集成电路" },
// { id: "通信网络", name: "通信网络" },
// { id: "量子科技", name: "量子科技" }
]);
// 修改获取科技领域列表,添加全选选项 // 修改获取科技领域列表,添加全选选项
const handleGetAreaList = async () => { const handleGetAreaList = async () => {
try { try {
...@@ -1048,8 +970,6 @@ const handleGetAreaList = async () => { ...@@ -1048,8 +970,6 @@ const handleGetAreaList = async () => {
console.log("行业领域列表", res); console.log("行业领域列表", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
areaList.value = res.data; areaList.value = res.data;
// 获取列表后重新查询
handleGetDecreeOrderList();
} }
} catch (error) { } } catch (error) { }
}; };
...@@ -1058,51 +978,46 @@ const totalDecreesNum = ref(0); ...@@ -1058,51 +978,46 @@ const totalDecreesNum = ref(0);
const decreeList = ref([]); const decreeList = ref([]);
// 修改请求方法,处理全选时不传参数的情况 // 科技政令库
const handleGetDecreeOrderList = async () => { const box9Params = reactive({
page: 1,
size: 10,
name: '',
sortFun: '0',
isCN: false,
loading: false,
})
const getDecreeList = async (page) => {
if (page) box9Params.page = page;
box9Params.loading = true;
const params = { const params = {
currentPage: currentPage.value, currentPage: box9Params.page,
pageSize: pageSize.value, pageSize: box9Params.size,
proposeName: box9Params.name,
isCN: box9Params.isCN ? 1 : 0,
sortFun: box9Params.sortFun,
typeIds: checkedDecreeType.value.join(',') || null,
researchTypeIds: activeAreaList.value.join(',') || null, researchTypeIds: activeAreaList.value.join(',') || null,
sortFun: isSort.value,
isCN: isChina.value ? 1 : 0,
proposeName: searchType.value,
years: activePubTime.value.join(',') || null, years: activePubTime.value.join(',') || null,
typeIds: checkedDecreeType.value.toString()
}; };
try { try {
const res = await getDecreeOrderList(params); const res = await getDecreeOrderList(params);
console.log("资源库列表", res); console.log("科技政令库", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
totalDecreesNum.value = res.data.totalElements; totalDecreesNum.value = res.data.totalElements;
decreeList.value = res.data.content.map(item => { decreeList.value = res.data.content;
return {
id: item.id,
time: item.postDate,
title: item.proposeOrgName + ": " + item.name,
desc: item.describe,
img: item.orgImage,
tagList: item.industryList
};
});
} else { } else {
decreeList.value = []; decreeList.value = [];
totalDecreesNum.value = 0; totalDecreesNum.value = 0;
} }
} catch (error) { } catch (error) {
console.error("资源库列表error", error);
decreeList.value = []; decreeList.value = [];
totalDecreesNum.value = 0; totalDecreesNum.value = 0;
} }
box9Params.loading = false;
}; };
watch([checkedGovIns, isSort, isChina, searchType], val => {
// 切换页码到第一页
currentPage.value = 1;
handleGetDecreeOrderList();
});
// 切换当前政令 // 切换当前政令
const handleSwithCurDecree = name => { const handleSwithCurDecree = name => {
if (name === "left") { if (name === "left") {
...@@ -1160,12 +1075,12 @@ onMounted(async () => { ...@@ -1160,12 +1075,12 @@ onMounted(async () => {
handleGetNews(); handleGetNews();
handleGetDecreeTypeList(); handleGetDecreeTypeList();
handleGetAreaList(); handleGetAreaList();
handleGetDecreeOrderList();
handleBox1(); // 最新科技政令 handleBox1(); // 最新科技政令
handleGetKeyDecree(); getBox5Data();
handleBox5(); getBox6Data();
handleBox6(); getBox7Data();
handleGetDecreeKeyInstruction(); getBox8Data();
getDecreeList();
}); });
</script> </script>
...@@ -1202,31 +1117,6 @@ onMounted(async () => { ...@@ -1202,31 +1117,6 @@ onMounted(async () => {
} }
} }
.data-origin-box {
width: 100%;
display: flex;
align-items: center;
padding: 16px 22px;
.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);
}
}
.home-wrapper { .home-wrapper {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -1638,17 +1528,14 @@ onMounted(async () => { ...@@ -1638,17 +1528,14 @@ onMounted(async () => {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between;
.box1-main-right-title { .box1-main-right-title {
width: 100%; width: 100%;
// height: 26px;
color: var(--color-main-active); color: var(--color-main-active);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: bold;
line-height: 26px; line-height: 30px;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
...@@ -1657,10 +1544,10 @@ onMounted(async () => { ...@@ -1657,10 +1544,10 @@ onMounted(async () => {
} }
.box1-main-right-info { .box1-main-right-info {
margin-top: 14px; margin-top: 10px;
display: flex; display: flex;
height: 24px;
gap: 8px; gap: 8px;
flex-wrap: wrap;
} }
.box1-main-right-center { .box1-main-right-center {
...@@ -1990,8 +1877,6 @@ onMounted(async () => { ...@@ -1990,8 +1877,6 @@ onMounted(async () => {
.box5-main { .box5-main {
flex: auto; flex: auto;
height: 20px; height: 20px;
padding-top: 16px;
.box5-chart { .box5-chart {
height: 100%; height: 100%;
} }
...@@ -2136,6 +2021,7 @@ onMounted(async () => { ...@@ -2136,6 +2021,7 @@ onMounted(async () => {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative;
.box8-header { .box8-header {
width: 100%; width: 100%;
...@@ -2189,10 +2075,10 @@ onMounted(async () => { ...@@ -2189,10 +2075,10 @@ onMounted(async () => {
margin-bottom: 6px; margin-bottom: 6px;
} }
.home-main-footer-header { .home-main-footer-head {
width: 1600px; width: 1600px;
height: 50px; height: 50px;
margin: 0 auto 16px; margin: 16px auto 22px;
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -2334,6 +2220,7 @@ onMounted(async () => { ...@@ -2334,6 +2220,7 @@ onMounted(async () => {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
box-sizing: border-box; box-sizing: border-box;
border-radius: 10px; border-radius: 10px;
overflow: hidden;
.content-header { .content-header {
height: 48px; height: 48px;
...@@ -2365,25 +2252,16 @@ onMounted(async () => { ...@@ -2365,25 +2252,16 @@ onMounted(async () => {
} }
.content-box { .content-box {
border-bottom: 1px solid rgba(234, 236, 238, 1);
overflow: hidden; overflow: hidden;
min-height: 790px; min-height: 480px;
box-sizing: border-box;
.main-item { .main-item {
display: flex; display: flex;
width: 100%; width: 100%;
min-height: 100px; min-height: 100px;
// height: 136px;
// background: orange;
box-sizing: border-box;
padding: 16px 36px 0px 0px; padding: 16px 36px 0px 0px;
cursor: pointer; cursor: pointer;
// &:hover {
// background: var(--color-bg-hover);
// }
.main-item-left { .main-item-left {
display: flex; display: flex;
gap: 18px; gap: 18px;
...@@ -2440,30 +2318,29 @@ onMounted(async () => { ...@@ -2440,30 +2318,29 @@ onMounted(async () => {
gap: 16px; gap: 16px;
.title { .title {
width: 20px;
flex: auto;
height: 26px; height: 26px;
line-height: 26px;
color: rgba(59, 65, 75, 1); color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 20px; font-size: 20px;
font-weight: 700; font-weight: bold;
line-height: 26px;
letter-spacing: 0px; letter-spacing: 0px;
flex: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
} }
.type-box { .type-box {
flex: none; flex: none;
height: 28px; height: 28px;
line-height: 28px; line-height: 28px;
padding: 0 8px; padding: 0 12px;
text-align: center; text-align: center;
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: 16px; font-size: 16px;
font-weight: 400; font-weight: 400;
letter-spacing: 0px; letter-spacing: 0px;
border-radius: 4px; border-radius: 14px;
margin-left: 20px;
} }
.type1 { .type1 {
...@@ -2504,8 +2381,8 @@ onMounted(async () => { ...@@ -2504,8 +2381,8 @@ onMounted(async () => {
} }
.footer-box { .footer-box {
margin: 20px 30px; border-top: 1px solid rgba(234, 236, 238, 1);
height: 32px; padding: 20px 30px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<div class="box1"> <div class="box1">
<AnalysisBox title="相关政令" :showAllBtn="false"> <AnalysisBox title="相关政令" :showAllBtn="false">
<div class="box1-main" v-loading="isLoading"> <div class="box1-main" v-loading="isLoading">
<el-empty v-if="!siderList?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" /> <el-empty v-if="!siderList?.length" style="height: 100%;" description="暂无数据" :image-size="100" />
<el-scrollbar height="100%" always> <el-scrollbar height="100%" always>
<div class="left-item" :class="{ 'item-active': false }" v-for="(item, index) in siderList" :key="index" @click="handleClickDecree(item)"> <div class="left-item" :class="{ 'item-active': false }" v-for="(item, index) in siderList" :key="index" @click="handleClickDecree(item)">
<div class="item-head"> <div class="item-head">
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<div class="box2"> <div class="box2">
<AnalysisBox title="政令关系挖掘" :showAllBtn="false"> <AnalysisBox title="政令关系挖掘" :showAllBtn="false">
<div style="height: 100%; width: 100%;" v-loading="isLoading"> <div style="height: 100%; width: 100%;" v-loading="isLoading">
<el-empty v-if="!siderList?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" /> <el-empty v-if="!siderList?.length" style="height: 100%;" description="暂无数据" :image-size="100" />
<div class="box2-main" v-if="graphData.nodes?.length"> <div class="box2-main" v-if="graphData.nodes?.length">
<GraphChart :nodes="graphData.nodes" :links="graphData.links" layoutType="force" @handleClickNode="handleClickNode" /> <GraphChart :nodes="graphData.nodes" :links="graphData.links" layoutType="force" @handleClickNode="handleClickNode" />
</div> </div>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="layout-container"> <div class="layout-container">
<!-- 导航菜单 --> <!-- 导航菜单 -->
<div class="layout-main"> <div class="layout-main">
<div class="header-main"> <div class="layout-head">
<div class="layout-main-header"> <div class="layout-main-header">
<div class="layout-main-header-container"> <div class="layout-main-header-container">
<div class="layout-main-header-left-box"> <div class="layout-main-header-left-box">
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="layout-main-center"> <div class="layout-down">
<router-view /> <router-view />
</div> </div>
</div> </div>
...@@ -208,68 +208,7 @@ onMounted(() => { ...@@ -208,68 +208,7 @@ onMounted(() => {
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
overflow-y: auto; overflow-y: auto;
background-color: white;
.report {
padding: 10px 150px;
position: absolute;
left: 0;
top: 0;
z-index: 999999;
width: 100%;
height: 100%;
background: #f7f8f9;
.report-header {
width: 100%;
height: 50px;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Bold;
font-size: 20px;
font-weight: 700;
line-height: 50px;
letter-spacing: 0px;
text-align: left;
padding-left: 30px;
border-bottom: 1px solid rgba(234, 236, 238, 1);
}
.report-main {
display: flex;
height: calc(100% - 100px);
justify-content: space-between;
.left {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
text-align: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
}
.right {
width: 800px;
.noContent {
height: 100px;
line-height: 100px;
text-align: center;
color: rgba(59, 65, 75, 1);
font-family: Microsoft YaHei;
font-style: Regular;
font-size: 20px;
font-weight: 400;
}
}
}
}
.layout-main { .layout-main {
width: 100%; width: 100%;
...@@ -277,10 +216,10 @@ onMounted(() => { ...@@ -277,10 +216,10 @@ onMounted(() => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.header-main { .layout-head {
width: 100%; width: 100%;
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgb(234, 236, 238);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1); box-shadow: 0 0 20px #1945821a;
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
} }
...@@ -288,7 +227,6 @@ onMounted(() => { ...@@ -288,7 +227,6 @@ onMounted(() => {
width: 1600px; width: 1600px;
height: 137px; height: 137px;
margin: 0 auto; margin: 0 auto;
background: rgba(255, 255, 255, 1);
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
position: sticky; position: sticky;
...@@ -526,10 +464,9 @@ onMounted(() => { ...@@ -526,10 +464,9 @@ onMounted(() => {
} }
} }
.layout-main-center { .layout-down {
height: 20px; height: 20px;
flex: auto; flex: auto;
background-color: #f7f8f9;
} }
} }
} }
......
<template> <template>
<div class="view-box"> <div class="view-box">
<el-empty v-if="!listData?.length" style="padding: 60px 0" description="暂无数据" :image-size="100" /> <el-empty v-if="!listData?.length" style="height: 100%;" description="暂无数据" :image-size="100" />
<div <div
v-if="listData.length" v-if="listData.length"
class="main-content-main" class="main-content-main"
...@@ -10,12 +10,8 @@ ...@@ -10,12 +10,8 @@
@mouseleave="handleMouseUp" @mouseleave="handleMouseUp"
@mousemove="handleMouseMove" @mousemove="handleMouseMove"
> >
<div <div class="fishbone-container"
class="fishbone-container" :style="{ transform: `translate(${translateX}px, ${translateY}px) scale(${scale})` }"
:style="{
transform: `translate(${translateX}px, ${translateY}px) scale(${scale})`,
transformOrigin: 'center center'
}"
> >
<!-- 主轴上的标签 --> <!-- 主轴上的标签 -->
<div class="main-line" :style="{ width: listData.length * 200 + 300 + 'px' }"> <div class="main-line" :style="{ width: listData.length * 200 + 300 + 'px' }">
...@@ -152,18 +148,18 @@ ...@@ -152,18 +148,18 @@
</template> </template>
<script setup name="ChartChain"> <script setup name="ChartChain">
import { ref } from "vue"; import { onBeforeUnmount, ref, watch } from "vue";
import defaultIcon2 from "@/assets/icons/default-icon2.png"; import defaultIcon2 from "@/assets/icons/default-icon2.png";
import noticeIcon from "../assets/images/notice-icon.png"; import noticeIcon from "../assets/images/notice-icon.png";
const props = defineProps({ const props = defineProps({
baseData: { baseData: {
type: Object, type: Array,
default: () => [] default: () => ([])
}, },
listData: { listData: {
type: Array, type: Array,
default: () => [] default: () => ([])
} }
}); });
...@@ -211,6 +207,15 @@ const handleMouseUp = () => { ...@@ -211,6 +207,15 @@ const handleMouseUp = () => {
}; };
// #endregion 移动功能处理 // #endregion 移动功能处理
// 初始化布局
const watchInfo = watch(() => props.listData, val => {
scale.value = 1;
translateX.value = 0;
translateY.value = 0;
})
onBeforeUnmount(() => { watchInfo() });
// 奇数索引的数据组放在上方, 偶数索引的数据组放在下方 // 奇数索引的数据组放在上方, 偶数索引的数据组放在下方
const onFilterData = num => { const onFilterData = num => {
return props.listData.filter((_, index) => index % 2 === num); return props.listData.filter((_, index) => index % 2 === num);
...@@ -247,9 +252,14 @@ const formatRate = (item, key) => { ...@@ -247,9 +252,14 @@ const formatRate = (item, key) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
overflow: hidden; overflow: hidden;
-webkit-user-select: none; /* Safari/Chrome */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none; /* 标准语法 */
.fishbone-container { .fishbone-container {
position: relative; position: relative;
transform-origin: center center;
.main-line { .main-line {
height: 3px; height: 3px;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</div> </div>
<div class="data-title">实体名称</div> <div class="data-title">实体名称</div>
<div style="height: 20px; flex: auto;"> <div style="height: 20px; flex: auto;">
<el-empty v-if="!entityInfo.list?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" /> <el-empty v-if="!entityInfo.list?.length" style="height: 100%;" description="暂无数据" :image-size="100" />
<el-scrollbar height="100%" always> <el-scrollbar height="100%" always>
<div class="list-data"> <div class="list-data">
<div class="list-item" v-for="item in entityInfo.list" :key="item.id" :class="{ 'item-active': entityInfo.id==item.id }" @click="headerChartData(item)"> <div class="list-item" v-for="item in entityInfo.list" :key="item.id" :class="{ 'item-active': entityInfo.id==item.id }" @click="headerChartData(item)">
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
</div> </div>
<div class="graph-box" v-if="contentType==2"> <div class="graph-box" v-if="contentType==2">
<GraphChart v-if="graphInfo.nodes?.length" :nodes="graphInfo.nodes" :links="graphInfo.links" layoutType="force" /> <GraphChart v-if="graphInfo.nodes?.length" :nodes="graphInfo.nodes" :links="graphInfo.links" layoutType="force" />
<el-empty v-else style="padding: 60px 0" description="暂无数据" :image-size="100" /> <el-empty v-else style="height: 100%;" description="暂无数据" :image-size="100" />
</div> </div>
</div> </div>
</AnalysisBox> </AnalysisBox>
...@@ -234,7 +234,6 @@ const onDecreeChainNodes = async (id) => { ...@@ -234,7 +234,6 @@ const onDecreeChainNodes = async (id) => {
} }
}) })
fishbone.list = Object.values(obj); fishbone.list = Object.values(obj);
console.log("fishbone.list:", fishbone.list);
fishbone.base = res.data.levelInfos.map((item, index) => { fishbone.base = res.data.levelInfos.map((item, index) => {
return {...item, name: ['上游', '中游', '下游'][index]} return {...item, name: ['上游', '中游', '下游'][index]}
}); });
...@@ -448,10 +447,13 @@ onMounted(() => { ...@@ -448,10 +447,13 @@ onMounted(() => {
:deep(.header-icon) { :deep(.header-icon) {
display: none; display: none;
} }
:deep(.wrapper-header) {
padding-top: 8px;
}
.custom-title { .custom-title {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: flex-end; align-items: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 0 20px; padding: 0 20px;
......
...@@ -5,10 +5,8 @@ ...@@ -5,10 +5,8 @@
<AnalysisBox title="提出背景" :showAllBtn="false"> <AnalysisBox title="提出背景" :showAllBtn="false">
<template #header-btn> <template #header-btn>
<div class="header-btn-box"> <div class="header-btn-box">
<div class="btn" :class="{ btnActive: box1ActiveBtn === item }" v-for="(item, index) in box1BtnList" <div class="btn" :class="{ btnActive: box1ActiveBtn === 1 }" @click="handleClickBox1Btn(1)">涉华背景</div>
:key="index" @click="handleClickBox1Btn(item)"> <div class="btn" :class="{ btnActive: box1ActiveBtn === 2 }" @click="handleClickBox1Btn(2)">全部背景</div>
{{ item }}
</div>
</div> </div>
</template> </template>
<div class="box1-container"> <div class="box1-container">
...@@ -17,9 +15,9 @@ ...@@ -17,9 +15,9 @@
<div class="box1-item" v-for="(item, index) in backgroundList" :key="index"> <div class="box1-item" v-for="(item, index) in backgroundList" :key="index">
<div class="id">{{ index + 1 }}</div> <div class="id">{{ index + 1 }}</div>
<div class="title text-align-justify">{{ item.content }}</div> <div class="title text-align-justify">{{ item.content }}</div>
<div class="open"> <!-- <div class="open">
<img src="./assets/images/open-icon.png" alt="" /> <img src="./assets/images/open-icon.png" alt="" />
</div> </div> -->
</div> </div>
</div> </div>
<div class="box1-footer" v-if="backgroundListNum > 10"> <div class="box1-footer" v-if="backgroundListNum > 10">
...@@ -32,15 +30,15 @@ ...@@ -32,15 +30,15 @@
</div> </div>
</AnalysisBox> </AnalysisBox>
</div> </div>
<div class="box2"> <div class="box2" v-loading="box2Params.loading">
<AnalysisBox title="法律依据" :showAllBtn="false"> <AnalysisBox title="法律依据" :showAllBtn="false">
<el-empty v-if="!dependList?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" /> <el-empty v-if="!box2Params.list?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" />
<div class="box2-main"> <div class="box2-main">
<div class="custom-collapse"> <div class="custom-collapse">
<el-collapse v-model="dependActive"> <el-collapse v-model="box2Params.active">
<el-collapse-item v-for="(item, index) in dependList" :key="item.billId" :name="item.billId"> <el-collapse-item v-for="(item, index) in box2Params.list" :key="item.billId" :name="item.billId">
<template #icon> <template #icon>
<el-icon v-if="dependActive.includes(item.billId)"> <el-icon v-if="box2Params.active.includes(item.billId)">
<ArrowDownBold /> <ArrowDownBold />
</el-icon> </el-icon>
<el-icon v-else> <el-icon v-else>
...@@ -92,7 +90,7 @@ ...@@ -92,7 +90,7 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from "vue"; import { ref, onMounted, reactive } from "vue";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { getDecreeBackground, getDecreeDepend, getDecreePrev } from "@/api/decree/background"; import { getDecreeBackground, getDecreeDepend, getDecreePrev } from "@/api/decree/background";
import router from "@/router"; import router from "@/router";
...@@ -104,8 +102,7 @@ const route = useRoute(); ...@@ -104,8 +102,7 @@ const route = useRoute();
const decreeId = ref(route.query.id); const decreeId = ref(route.query.id);
// 提出背景 // 提出背景
const box1BtnList = ref(["涉华背景", "全部背景"]); const box1ActiveBtn = ref(1);
const box1ActiveBtn = ref("涉华背景");
const handleClickBox1Btn = btn => { const handleClickBox1Btn = btn => {
box1ActiveBtn.value = btn; box1ActiveBtn.value = btn;
handleCurrentChange(1) handleCurrentChange(1)
...@@ -126,7 +123,7 @@ const handleCurrentChange = page => { ...@@ -126,7 +123,7 @@ const handleCurrentChange = page => {
}; };
const handleGetBackground = async () => { const handleGetBackground = async () => {
const params = { const params = {
cRelated: box1ActiveBtn.value === "涉华背景" ? true : false, cRelated: box1ActiveBtn.value === 1,
currentPage: currentPage.value - 1, currentPage: currentPage.value - 1,
pageSize: 10, pageSize: 10,
id: decreeId.value id: decreeId.value
...@@ -144,7 +141,6 @@ const handleGetBackground = async () => { ...@@ -144,7 +141,6 @@ const handleGetBackground = async () => {
} catch (error) { } catch (error) {
backgroundListNum.value = 0; backgroundListNum.value = 0;
backgroundList.value = []; backgroundList.value = [];
console.error("获取提出背景数据失败", error);
} }
}; };
...@@ -167,7 +163,6 @@ const handleGetPrev = async () => { ...@@ -167,7 +163,6 @@ const handleGetPrev = async () => {
} }
} catch (error) { } catch (error) {
prevList.value = []; prevList.value = [];
console.error("获取前序政令数据失败", error);
} }
}; };
// 跳转行政机构主页 // 跳转行政机构主页
...@@ -205,22 +200,25 @@ const handleClickDecree = item => { ...@@ -205,22 +200,25 @@ const handleClickDecree = item => {
}; };
// 法律依据 // 法律依据
const dependList = ref([]); const box2Params = reactive({
const dependActive = ref([]); loading: false,
active: [],
list: [],
})
const handleGetLaws = async () => { const handleGetLaws = async () => {
box2Params.loading = true;
try { try {
const res = await getDecreeDepend({ id: decreeId.value }); const res = await getDecreeDepend({ id: decreeId.value });
console.log("法律依据", res); console.log("法律依据", res);
if (res.code === 200 && res.data) { if (res.code === 200 && res.data) {
dependList.value = res.data; box2Params.list = res.data;
// dependActive.value = res.data.map(item => item.billId);
} else { } else {
dependList.value = []; box2Params.list = [];
} }
} catch (error) { } catch (error) {
dependList.value = []; box2Params.list = [];
console.error("获取法律依据数据失败", error);
} }
box2Params.loading = false;
}; };
// 跳转科技法案详情页 // 跳转科技法案详情页
const handleClickBull = decree => { const handleClickBull = decree => {
...@@ -290,10 +288,11 @@ onMounted(() => { ...@@ -290,10 +288,11 @@ onMounted(() => {
} }
.box1-main { .box1-main {
width: 1034px; width: 100%;
padding: 0 6px;
.box1-item { .box1-item {
width: 1015px; width: 100%;
min-height: 48px; min-height: 48px;
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: var(--font-size-base); font-size: var(--font-size-base);
...@@ -302,11 +301,10 @@ onMounted(() => { ...@@ -302,11 +301,10 @@ onMounted(() => {
background: rgba(255, 255, 255, 1); background: rgba(255, 255, 255, 1);
display: flex; display: flex;
align-items: center; align-items: center;
padding: 18px 0; padding: 18px 16px;
.id { .id {
margin-right: 16px; margin-right: 16px;
margin-left: 15px;
width: 24px; width: 24px;
height: 24px; height: 24px;
text-align: center; text-align: center;
...@@ -357,9 +355,8 @@ onMounted(() => { ...@@ -357,9 +355,8 @@ onMounted(() => {
} }
.box2 { .box2 {
.box2-main { .box2-main {
padding: 16px 20px; padding: 10px 24px 16px;
.custom-collapse { .custom-collapse {
padding-left: 32px; padding-left: 32px;
...@@ -371,6 +368,8 @@ onMounted(() => { ...@@ -371,6 +368,8 @@ onMounted(() => {
:deep(.el-collapse-item__header) { :deep(.el-collapse-item__header) {
border-bottom: 1px solid rgba(234, 236, 238, 1); border-bottom: 1px solid rgba(234, 236, 238, 1);
min-height: 50px;
line-height: 50px;
} }
:deep(.el-collapse-item__content) { :deep(.el-collapse-item__content) {
...@@ -384,18 +383,19 @@ onMounted(() => { ...@@ -384,18 +383,19 @@ onMounted(() => {
font-family: Microsoft YaHei; font-family: Microsoft YaHei;
font-size: var(--font-size-base); font-size: var(--font-size-base);
position: absolute; position: absolute;
top: 12px; top: 13px;
left: -32px; left: -32px;
width: 24px; width: 24px;
height: 24px; height: 24px;
text-align: center;
line-height: 24px; line-height: 24px;
text-align: center;
border-radius: 50%; border-radius: 50%;
background: #e7f3ff; background: #e7f3ff;
color: #0a57a6; color: #0a57a6;
} }
.custom-collapse-name { .custom-collapse-name {
padding-left: 6px;
font-weight: 600; font-weight: 600;
font-size: 18px; font-size: 18px;
color: var(--el-collapse-header-text-color); color: var(--el-collapse-header-text-color);
......
...@@ -70,7 +70,6 @@ onMounted(() => { ...@@ -70,7 +70,6 @@ onMounted(() => {
.decree-overview-wrap { .decree-overview-wrap {
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
background: rgba(247, 248, 249, 1);
.main { .main {
position: relative; position: relative;
width: 1600px; width: 1600px;
......
...@@ -145,7 +145,7 @@ ...@@ -145,7 +145,7 @@
<div class="box3-bottom-main"> <div class="box3-bottom-main">
<el-timeline style="max-width: 500px"> <el-timeline style="max-width: 500px">
<el-timeline-item :timestamp="item.postDate" placement="top" v-for="(item, index) in eventList?.slice(0, 3)" :key="index"> <el-timeline-item :timestamp="item.postDate" placement="top" v-for="(item, index) in eventList?.slice(0, 3)" :key="index">
<div class="timeline-content">{{ item.describe }}</div> <div class="timeline-content text-align-justify">{{ item.describe }}</div>
</el-timeline-item> </el-timeline-item>
</el-timeline> </el-timeline>
</div> </div>
...@@ -789,6 +789,12 @@ onMounted(() => { ...@@ -789,6 +789,12 @@ onMounted(() => {
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 26px; line-height: 26px;
max-height: 78px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
} }
} }
} }
......
<template> <template>
<div class="introduction-wrap"> <div class="introduction-wrap">
<div class="page-left"> <div class="page-left">
<div class="box1"> <div class="box1" v-loading="box1Params.loading">
<AnalysisBox title="主要指令" :showAllBtn="false"> <AnalysisBox title="主要指令" :showAllBtn="false">
<template #header-btn> <template #header-btn>
<div class="mind-bnt" @click="onDecreeMindMap()"> <div class="mind-bnt" @click="onDecreeMindMap()">
...@@ -23,18 +23,18 @@ ...@@ -23,18 +23,18 @@
<div style="margin-left: 6px;">高亮实体</div> --> <div style="margin-left: 6px;">高亮实体</div> -->
<div class="select-input"> <div class="select-input">
<el-input v-model="commandWord" @keyup.enter="onMainContentData()" style="width: 100%; height: 100%;" <el-input v-model="commandWord" @keyup.enter="onMainContentData()" style="width: 100%; height: 100%;"
:suffix-icon="Search" placeholder="指令搜索" /> :prefix-icon="Search" placeholder="指令搜索" clearable @clear="onMainContentData()" />
</div> </div>
</div> </div>
<div class="analysis-content"> <div class="analysis-content">
<!-- 遍历文档章节 --> <!-- 遍历文档章节 -->
<el-empty v-if="!contentList?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" /> <el-empty v-if="!contentList?.length" style="padding: 80px 0 96px;" description="暂无数据" :image-size="100" />
<div v-for="(section, index) in contentList" :key="index" class="section"> <div v-for="(section, index) in contentList" :key="index" class="section">
<div class="section-header"> <div class="section-header">
<div class="section-title text-align-justify" v-html="section.content"></div> <div class="section-title text-align-justify" v-html="section.content"></div>
<div class="section-icon"> <!-- <div class="section-icon">
<img src="./assets/images/open-icon.png" alt="" /> <img src="./assets/images/open-icon.png" alt="" />
</div> </div> -->
</div> </div>
<!-- 渲染一级列表 --> <!-- 渲染一级列表 -->
<div class="numbered-list"> <div class="numbered-list">
...@@ -67,22 +67,21 @@ ...@@ -67,22 +67,21 @@
</div> </div>
</div> </div>
<div class="page-right"> <div class="page-right">
<div class="box3"> <div class="box3" v-loading="orgInfo.loading">
<AnalysisBox title="执行机构" :showAllBtn="false"> <AnalysisBox title="执行机构" :showAllBtn="false">
<div class="box3-top"> <div class="box3-top" v-if="orgInfo.list?.length">
<div class="organization-list"> <div class="organization-list">
<div class="organization-item" v-for="item in organizationInfo.list" :key="item.id"> <div class="organization-item" v-for="item in orgInfo.list" :key="item.id">
<ActionButton @click="handleOrganization(item)" :name="item.obb" <ActionButton @click="handleOrganization(item)" :name="item.obb" :type="item.id == orgInfo.node.id ? 'active' : 'normal'" />
:type="item.id == organizationInfo.node.id ? 'active' : 'normal'" />
</div> </div>
</div> </div>
<div class="box3-top-top" @click="handleToInstitution()"> <div class="box3-top-top">
<div class="left"> <div class="left">
<img :src="organizationInfo.node.logo || DefaultIcon2" alt="" /> <img :src="orgInfo.node.logo || DefaultIcon2" alt="" />
</div> </div>
<div class="right"> <div class="right">
<div class="name">{{ organizationInfo.node.name + " >" }}</div> <div class="name text-click-hover" @click="handleToInstitution()">{{ orgInfo.node.name + " >" }}</div>
<div class="ename">{{ organizationInfo.node.ename }}</div> <div class="ename">{{ orgInfo.node.ename }}</div>
</div> </div>
</div> </div>
<div class="box3-top-bottom"> <div class="box3-top-bottom">
...@@ -93,7 +92,8 @@ ...@@ -93,7 +92,8 @@
<div class="text">{{ "关键人物" }}</div> <div class="text">{{ "关键人物" }}</div>
</div> </div>
<div class="box3-top-bottom-main"> <div class="box3-top-bottom-main">
<div class="box3-top-bottom-item" v-for="(item, index) in organizationInfo.node.leaders" :key="index"> <el-empty v-if="!orgInfo.node.leaders?.length" style="width:100%; height:100%;" description="暂无数据" :image-size="60" />
<div class="box3-top-bottom-item" v-for="(item, index) in orgInfo.node.leaders" :key="index">
<div class="box3-top-bottom-item-left"> <div class="box3-top-bottom-item-left">
<img :src="item.avatar || DefaultIcon1" alt="" /> <img :src="item.avatar || DefaultIcon1" alt="" />
</div> </div>
...@@ -112,32 +112,34 @@ ...@@ -112,32 +112,34 @@
</el-icon> </el-icon>
</div> </div>
</div> </div>
<el-empty v-else style="padding: 98px 0 138px;" description="暂无数据" :image-size="100" />
</AnalysisBox> </AnalysisBox>
</div> </div>
<div class="box4"> <div class="box4" v-loading="box4Params.loading">
<AnalysisBox title="相关实体" :showAllBtn="false"> <AnalysisBox title="相关实体" :showAllBtn="false">
<el-empty v-if="!entityList?.length" style="padding: 60px 0;" description="暂无数据" :image-size="100" /> <div v-if="box4Params.list?.length" class="left-bottom-main">
<div class="left-bottom-main"> <div v-for="(item, index) in box4Params.list" :key="index" class="main-box">
<div v-for="(item, index) in entityList" :key="index" class="main-box">
<div class="icon"> <div class="icon">
<img style="width: 100%; height: 100%;" :src="item.imgUrl || defaultCom" alt="" /> <img style="width: 100%; height: 100%;" :src="item.imgUrl || defaultCom" alt="" />
</div> </div>
<div class="name one-line-ellipsis">{{ item.name }}</div> <div class="name one-line-ellipsis text-click-hover" @click="handleSearch(item)">{{ item.name }}</div>
<div class="type">{{ item.entityType }}</div> <div class="type">{{ item.entityType }}</div>
</div> </div>
</div> </div>
<el-empty v-else style="padding: 60px 0 100px;" description="暂无数据" :image-size="100" />
</AnalysisBox> </AnalysisBox>
</div> </div>
</div> </div>
<el-dialog v-model="isTreeDialog" width="1400px" top="8vh" class="viewpoint-dialog" destroy-on-close> <el-dialog v-model="mindParams.isShow" width="1400px" top="8vh" class="viewpoint-dialog" destroy-on-close>
<template #header> <template #header>
<div class="viewpoint-header"> <div class="viewpoint-header">
<div class="viewpoint-title">政令举措思维导图</div> <div class="viewpoint-title">政令举措思维导图</div>
</div> </div>
</template> </template>
<div class="viewpoint-body"> <div class="viewpoint-body" v-loading="mindParams.loading">
<MindGraph ref="refMindGraph"></MindGraph> <MindGraph v-if="mindParams.isData" ref="refMindGraph"></MindGraph>
<el-empty v-else style="height: 100%;" description="暂无数据" :image-size="100" />
</div> </div>
</el-dialog> </el-dialog>
</div> </div>
...@@ -179,7 +181,6 @@ const handleGetAreaList = async () => { ...@@ -179,7 +181,6 @@ const handleGetAreaList = async () => {
} }
} catch (error) { } catch (error) {
areaList.value = [] areaList.value = []
console.error("获取科技领域数据失败:", error);
} }
}; };
...@@ -188,7 +189,11 @@ const isHighlight = ref(false); ...@@ -188,7 +189,11 @@ const isHighlight = ref(false);
const commandWord = ref(""); const commandWord = ref("");
const contentList = ref([]); const contentList = ref([]);
const ALPHABET = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]; const ALPHABET = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
const box1Params = reactive({
loading: false,
})
const onMainContentData = async () => { const onMainContentData = async () => {
box1Params.loading = true;
try { try {
const keyword = commandWord.value; const keyword = commandWord.value;
const res = await getDecreeMainContent({ id: route.query.id, keyword, domainId: areaType.value }); const res = await getDecreeMainContent({ id: route.query.id, keyword, domainId: areaType.value });
...@@ -205,8 +210,8 @@ const onMainContentData = async () => { ...@@ -205,8 +210,8 @@ const onMainContentData = async () => {
} }
} catch (error) { } catch (error) {
contentList.value = [] contentList.value = []
console.error("获取主要指令数据失败:", error);
} }
box1Params.loading = false;
}; };
// 搜索高亮效果 // 搜索高亮效果
const onHighlight = (word, row) => { const onHighlight = (word, row) => {
...@@ -219,9 +224,15 @@ const onHighlight = (word, row) => { ...@@ -219,9 +224,15 @@ const onHighlight = (word, row) => {
} }
// 思维导图 // 思维导图
const isTreeDialog = ref(false);
const refMindGraph = ref(null); const refMindGraph = ref(null);
const mindParams = reactive({
isData: true,
loading: false,
isShow: false,
})
const onDecreeMindMap = async () => { const onDecreeMindMap = async () => {
mindParams.loading = true;
mindParams.isData = true;
let labelCfg = { let labelCfg = {
position: 'left', position: 'left',
offset: -20, offset: -20,
...@@ -232,11 +243,11 @@ const onDecreeMindMap = async () => { ...@@ -232,11 +243,11 @@ const onDecreeMindMap = async () => {
autoWrap: true autoWrap: true
} }
} }
isTreeDialog.value = true; mindParams.isShow = true;
try { try {
let res = await getDecreeMindMap({ id: route.query.id }); let res = await getDecreeMindMap({ id: route.query.id });
console.log("思维导图", res); console.log("思维导图", res);
if (res.code === 200) { if (res.code === 200 && res.data) {
let nodes = [] let nodes = []
let edges = [] let edges = []
let obj = {} let obj = {}
...@@ -256,12 +267,14 @@ const onDecreeMindMap = async () => { ...@@ -256,12 +267,14 @@ const onDecreeMindMap = async () => {
edges.push({ id: `edge-${index}`, source: `root-virtual`, target: `node-${item.orderNum}-${item.sectionId}` }) edges.push({ id: `edge-${index}`, source: `root-virtual`, target: `node-${item.orderNum}-${item.sectionId}` })
} }
}) })
setTimeout(() => { refMindGraph.value.onMindGraphData(nodes, edges) }, 100) setTimeout(() => { refMindGraph.value.onMindGraphData(nodes, edges) }, 100)
} else {
mindParams.isData = false
} }
} catch (error) { } catch (error) {
console.error("获取思维导图数据失败:", error); mindParams.isData = false
} }
mindParams.loading = false
} }
// 对象数组去重 // 对象数组去重
...@@ -277,50 +290,64 @@ const onUniqueArray = (list, key = 'id') => { ...@@ -277,50 +290,64 @@ const onUniqueArray = (list, key = 'id') => {
} }
// 相关实体 // 相关实体
const entityList = ref([]); const box4Params = reactive({
loading: false,
list: [],
})
const onRelatedEntityData = async () => { const onRelatedEntityData = async () => {
box4Params.loading = true;
try { try {
const res = await getDecreeRelatedEntity({ id: route.query.id }); const res = await getDecreeRelatedEntity({ id: route.query.id });
console.log("相关实体", res); console.log("相关实体", res);
if (res && res.code === 200) { if (res && res.code === 200) {
entityList.value = res.data; box4Params.list = res.data;
} else { } else {
entityList.value = [] box4Params.list = []
} }
} catch (error) { } catch (error) {
entityList.value = [] box4Params.list = []
console.error("获取相关实体数据失败:", error);
} }
box4Params.loading = false;
};
const handleSearch = (item) => {
window.sessionStorage.setItem("curTabName", `搜索-${item.name}`);
const curRoute = router.resolve({
path: "/searchResults",
query: {searchText: item.name}
});
window.open(curRoute.href, "_blank");
}; };
// 执行机构 // 执行机构
const organizationInfo = reactive({ const orgInfo = reactive({
loading: false,
list: [], list: [],
node: { id: "", obb: "", logo: "", name: "", ename: "", leaders: [] }, node: { id: "", obb: "", logo: "", name: "", ename: "", leaders: [] },
}) })
const handleGetOrgnization = async () => { const handleGetOrgnization = async () => {
orgInfo.loading = true
try { try {
const res = await getDecreeOrganization({ id: route.query.id }); const res = await getDecreeOrganization({ id: route.query.id });
console.log("执行机构", res); console.log("执行机构", res);
if (res.code === 200 && res.data?.length) { if (res.code === 200 && res.data?.length) {
organizationInfo.list = res.data; orgInfo.list = res.data;
organizationInfo.node = res.data[0]; orgInfo.node = res.data[0];
} }
} catch (error) { } catch (error) {
organizationInfo.node = { id: "", obb: "", logo: "", name: "", ename: "", leaders: [] }; orgInfo.node = { id: "", obb: "", logo: "", name: "", ename: "", leaders: [] };
console.error("获取执行机构数据失败", error);
} }
orgInfo.loading = false;
}; };
// 切换执行机构 // 切换执行机构
const handleOrganization = (node) => { const handleOrganization = (node) => {
organizationInfo.node = node; orgInfo.node = node;
}; };
// 跳转机构主页 // 跳转机构主页
const handleToInstitution = () => { const handleToInstitution = () => {
const curRoute = router.resolve({ const curRoute = router.resolve({
path: "/institution", path: "/institution",
query: { query: {
id: organizationInfo.node.id id: orgInfo.node.id
} }
}); });
window.open(curRoute.href, "_blank"); window.open(curRoute.href, "_blank");
...@@ -450,6 +477,9 @@ onMounted(() => { ...@@ -450,6 +477,9 @@ onMounted(() => {
letter-spacing: 1px; letter-spacing: 1px;
width: 20px; width: 20px;
flex: auto; flex: auto;
font-weight: bold;
color: var(--text-primary-80-color);
font-family: Source Han Sans CN;
} }
.section-icon { .section-icon {
...@@ -468,7 +498,9 @@ onMounted(() => { ...@@ -468,7 +498,9 @@ onMounted(() => {
margin-bottom: 12px; margin-bottom: 12px;
font-size: 16px; font-size: 16px;
line-height: 1.7; line-height: 1.7;
color: #374151; color: var(--text-primary-80-color);
font-family: Source Han Sans CN;
font-size: 16px;
.list-item { .list-item {
position: relative; position: relative;
...@@ -542,7 +574,7 @@ onMounted(() => { ...@@ -542,7 +574,7 @@ onMounted(() => {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 16px; margin-bottom: 16px;
gap: 8px 16px; gap: 8px 8px;
} }
.organization-button { .organization-button {
...@@ -571,7 +603,6 @@ onMounted(() => { ...@@ -571,7 +603,6 @@ onMounted(() => {
background: rgba(247, 248, 249, 1); background: rgba(247, 248, 249, 1);
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer;
.left { .left {
width: 64px; width: 64px;
...@@ -798,7 +829,6 @@ onMounted(() => { ...@@ -798,7 +829,6 @@ onMounted(() => {
padding: 0 15px; padding: 0 15px;
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer;
.icon { .icon {
width: 24px; width: 24px;
......
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
<DivideHeader id="position3" class="divide-header" :titleText="'数据总览'"></DivideHeader> <DivideHeader id="position3" class="divide-header" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer"> <div class="center-footer">
<div class="box5"> <div class="box5">
<OverviewNormalBox title="数量变化趋势"> <OverviewNormalBox title="数量变化趋势" width="auto" height="100%">
<template #header-icon> <template #header-icon>
<img style="width: 100%; height: 100%;" src="./assets/icons/icon2.svg" alt="" /> <img style="width: 100%; height: 100%;" src="./assets/icons/icon2.svg" alt="" />
</template> </template>
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<el-empty v-if="!box5ChartData.title.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" /> <el-empty v-if="!box5ChartData.title.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" />
<div v-if="box5ChartData.title.length" style="width: 100%; height: 100%;" ref="box5Ref"></div> <div v-if="box5ChartData.title.length" style="width: 100%; height: 100%;" ref="box5Ref"></div>
</div> </div>
<TipTab text="美对华发起调查案件数量变化趋势,数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" style="margin-top: 16px;" /> <TipTab text="数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" style="margin-top: 16px;" />
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
<AiPane :aiContent="aiContent.content5" /> <AiPane :aiContent="aiContent.content5" />
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
</OverviewNormalBox> </OverviewNormalBox>
</div> </div>
<div class="box6"> <div class="box6">
<OverviewNormalBox title="领域分布情况" width="521px"> <OverviewNormalBox title="领域分布情况" width="auto" height="100%">
<template #header-icon> <template #header-icon>
<img style="width: 100%; height: 100%;" src="./assets/icons/icon3.svg" alt="" /> <img style="width: 100%; height: 100%;" src="./assets/icons/icon3.svg" alt="" />
</template> </template>
...@@ -122,7 +122,7 @@ ...@@ -122,7 +122,7 @@
<el-empty v-if="!box6Data.title.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" /> <el-empty v-if="!box6Data.title.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" />
<div v-if="box6Data.title.length" style="width: 100%; height: 100%;" id="box6Chart"></div> <div v-if="box6Data.title.length" style="width: 100%; height: 100%;" id="box6Chart"></div>
</div> </div>
<TipTab text="美对华发起调查案件领域分布情况,数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" ellipsis style="padding-right: 50px;" /> <TipTab text="数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" style="padding-right: 50px;" />
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
<AiPane :aiContent="aiContent.content6" /> <AiPane :aiContent="aiContent.content6" />
...@@ -133,7 +133,7 @@ ...@@ -133,7 +133,7 @@
</div> </div>
<div class="center-footer1"> <div class="center-footer1">
<div class="box7"> <div class="box7">
<OverviewNormalBox title="国家分布情况" width="1064px"> <OverviewNormalBox title="国家分布情况" width="auto" height="100%">
<template #header-icon> <template #header-icon>
<img style="width: 100%; height: 100%;" src="./assets/icons/icon4.svg" alt="" /> <img style="width: 100%; height: 100%;" src="./assets/icons/icon4.svg" alt="" />
</template> </template>
...@@ -154,7 +154,7 @@ ...@@ -154,7 +154,7 @@
<el-empty v-if="!box7Data.data.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" /> <el-empty v-if="!box7Data.data.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" />
<div v-if="box7Data.data.length" style="width: 100%; height: 100%;" id="box7Chart"></div> <div v-if="box7Data.data.length" style="width: 100%; height: 100%;" id="box7Chart"></div>
</div> </div>
<TipTab :text="`美发起调查案件的被调查国家分布情况,数据来源:${box7TipText}`" style="margin-top: 10px;" /> <TipTab :text="`数据来源:${box7TipText}`" style="margin-top: 10px;" />
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
<AiPane :aiContent="aiContent.content7" /> <AiPane :aiContent="aiContent.content7" />
...@@ -163,7 +163,7 @@ ...@@ -163,7 +163,7 @@
</OverviewNormalBox> </OverviewNormalBox>
</div> </div>
<div class="box8"> <div class="box8">
<OverviewNormalBox title="结果分布情况" width="521px"> <OverviewNormalBox title="结果分布情况" width="auto" height="100%">
<template #header-icon> <template #header-icon>
<img style="width: 100%; height: 100%" src="./assets/icons/icon5.svg" alt="" /> <img style="width: 100%; height: 100%" src="./assets/icons/icon5.svg" alt="" />
</template> </template>
...@@ -179,7 +179,7 @@ ...@@ -179,7 +179,7 @@
<el-empty v-if="!box8Data.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" /> <el-empty v-if="!box8Data.length" description="暂无数据" style="padding: 100px 0 0;" :image-size="100" />
<div v-if="box8Data.length" style="width: 100%; height: 100%;" ref="box8Ref"></div> <div v-if="box8Data.length" style="width: 100%; height: 100%;" ref="box8Ref"></div>
</div> </div>
<TipTab :text="`美发起调查案件的被调查国家分布情况,数据来源:${box8TipText}`" ellipsis style="padding-right: 50px;" /> <TipTab :text="`数据来源:${box8TipText}`" style="padding-right: 50px;" />
<div class="ai-pane"> <div class="ai-pane">
<AiButton /> <AiButton />
<AiPane :aiContent="aiContent.content8" /> <AiPane :aiContent="aiContent.content8" />
...@@ -304,7 +304,7 @@ import { getDateBefore, getAIReport, getNearYearList } from "@/views/marketAcces ...@@ -304,7 +304,7 @@ import { getDateBefore, getAIReport, getNearYearList } from "@/views/marketAcces
import router from "@/router"; import router from "@/router";
import { navigateToViewRiskSignal } from "@/utils/riskSignalOverviewNavigate"; import { navigateToViewRiskSignal } from "@/utils/riskSignalOverviewNavigate";
import createLineChart from "@/views/marketAccessRestrictions/utils/baseLineChart"; import createLineChart from "@/views/marketAccessRestrictions/utils/baseLineChart.js";
import createPieChart from "@/views/marketAccessRestrictions/utils/basePiechart.js"; import createPieChart from "@/views/marketAccessRestrictions/utils/basePiechart.js";
import getRadarChart from "./utils/radarChart"; import getRadarChart from "./utils/radarChart";
import getBarChart from "./utils/barChart1"; import getBarChart from "./utils/barChart1";
...@@ -863,7 +863,7 @@ const handleGetBox8Data = async () => { ...@@ -863,7 +863,7 @@ const handleGetBox8Data = async () => {
box8Data.value = [] box8Data.value = []
aiContent.content8 = ""; aiContent.content8 = "";
} }
nextTick(() => { createPieChart(box8Ref, box8Data.value, {labelType:1}) }) nextTick(() => { createPieChart(box8Ref, box8Data.value) })
}; };
// 资源库 // 资源库
...@@ -1814,15 +1814,16 @@ onMounted(async () => { ...@@ -1814,15 +1814,16 @@ onMounted(async () => {
} }
.center-footer { .center-footer {
margin-top: 21px; margin: 21px auto 0;
height: 460px; height: 460px;
display: flex; display: flex;
justify-content: center; gap: 16px;
gap: 15px; width: 1600px;
.box5 { .box5 {
width: 1064px; width: 20px;
height: 460px; flex: auto;
height: 100%;
.box-header-right { .box-header-right {
height: 48px; height: 48px;
...@@ -1865,8 +1866,9 @@ onMounted(async () => { ...@@ -1865,8 +1866,9 @@ onMounted(async () => {
} }
.box6 { .box6 {
width: 521px; width: 20px;
height: 460px; flex: auto;
height: 100%;
.box-header-right { .box-header-right {
height: 48px; height: 48px;
...@@ -1879,14 +1881,16 @@ onMounted(async () => { ...@@ -1879,14 +1881,16 @@ onMounted(async () => {
} }
.center-footer1 { .center-footer1 {
margin-top: 16px; margin: 16px auto 0;
height: 460px;
display: flex; display: flex;
justify-content: center; gap: 16px;
gap: 15px; width: 1600px;
.box7 { .box7 {
width: 1064px; width: 20px;
height: 460px; flex: auto;
height: 100%;
.box-header-right { .box-header-right {
height: 48px; height: 48px;
...@@ -1903,8 +1907,9 @@ onMounted(async () => { ...@@ -1903,8 +1907,9 @@ onMounted(async () => {
} }
.box8 { .box8 {
width: 521px; width: 20px;
height: 460px; flex: auto;
height: 100%;
.box-header-right { .box-header-right {
height: 48px; height: 48px;
......
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { MUTICHARTCOLORS } from '@/common/constant' import { MUTICHARTCOLORS } from '@/common/constant'
const truncateLabel = (value, maxLen = 6) => {
if (value === null || value === undefined) return ''
const str = String(value)
const chars = Array.from(str)
if (chars.length <= maxLen) return str
return `${chars.slice(0, maxLen).join('')}...`
}
const formatLabel = (node, type) => {
if (type==1) {
const name = truncateLabel(node.name, 6)
return `{name|${name}}\n{time|${ node.percent||0}%}`
}
return `{name|${node.name}} {time| ${node.value}${ node.percent||0}%}\n`
}
const createPieChart = (chartDom, data=[], option={}) => { const createPieChart = (chartDom, data=[], option={}) => {
if (!chartDom.value) return; if (!chartDom.value) return;
...@@ -46,21 +30,21 @@ const createPieChart = (chartDom, data=[], option={}) => { ...@@ -46,21 +30,21 @@ const createPieChart = (chartDom, data=[], option={}) => {
}, },
label: { label: {
alignTo: 'edge', alignTo: 'edge',
formatter: (node) => formatLabel(node, option.labelType), formatter: (node) => `{name|${node.name}}\n{time|${node.value}${ node.percent||0}%}`,
minMargin: 5, minMargin: 5,
edgeDistance: 10, edgeDistance: 10,
lineHeight: 22, lineHeight: 26,
rich: { rich: {
name: { name: {
color: 'rgba(59, 65, 75, 1)', color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei', fontFamily: 'Source Han Sans CN',
fontSize: 16, fontSize: 16,
fontWeight: 'bold', fontWeight: 'bold',
padding: [10, 0, 10, 0] padding: [10, 0, 10, 0]
}, },
time: { time: {
color: 'rgba(95, 101, 108, 1)', color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei', fontFamily: 'Source Han Sans CN',
fontSize: 16, fontSize: 16,
padding: [10, 0, 10, 0] padding: [10, 0, 10, 0]
} }
......
...@@ -61,12 +61,9 @@ export const getNearYearList = (num=6) => { ...@@ -61,12 +61,9 @@ export const getNearYearList = (num=6) => {
* AI智能总结 * AI智能总结
* @param data 需要分析的数据 * @param data 需要分析的数据
*/ */
export const getAIReport = async (data:any) => { export const getAIReport = async (data: any, timeoutMs: number = 10000): Promise<string> => {
let word = ""
// 👇 新增:超时 + 终止请求(只加这一段)
const controller = new AbortController(); const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10*1000); // 10秒超时 const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
try { try {
const res = await fetch('/aiAnalysis/chart_interpretation', { const res = await fetch('/aiAnalysis/chart_interpretation', {
...@@ -75,37 +72,40 @@ export const getAIReport = async (data:any) => { ...@@ -75,37 +72,40 @@ export const getAIReport = async (data:any) => {
"X-API-Key": "aircasKEY19491001", "X-API-Key": "aircasKEY19491001",
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({text: JSON.stringify(data)}), body: JSON.stringify({ text: JSON.stringify(data) }),
signal: controller.signal // 👇 新增:绑定中断信号 signal: controller.signal
}); });
clearTimeout(timeout); // 👇 新增:请求成功清除定时器 clearTimeout(timeoutId);
if (!res.ok) throw new Error(`HTTP 错误 ${res.status}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const reader = res.body.getReader(); const reader = res.body.getReader();
const decoder = new TextDecoder(); const decoder = new TextDecoder();
let result = '';
let buffer = ''; // 添加读取超时
let summarize = ''; const readTimeout = setTimeout(() => {
reader.cancel();
}, timeoutMs);
try {
while (true) { while (true) {
const { done, value } = await reader.read(); const { done, value } = await reader.read();
if (done) break; if (done) break;
const chunk = decoder.decode(value, { stream: true });
buffer += decoder.decode(value, { stream: true }); const match = chunk.match(/"解读":\s*"([^"]*)"/);
const lines = buffer.split('\n'); if (match?.[1]) {
buffer = lines.pop() || ''; result = match[1];
break; // 获取到结果立即结束
for (const line of lines) {
if (line.startsWith('data: ')) {
const content = line.substring(6);
const textMatch = content.match(/"解读":\s*"([^"]*)"/);
if (textMatch && textMatch[1]) summarize = textMatch[1];
} }
} }
} finally {
clearTimeout(readTimeout);
reader.cancel(); // 确保连接关闭
} }
word = summarize return result || "未获取到解读内容";
} catch (err) { } catch (err) {
word = "系统异常,生成失败"; return "系统异常,生成失败";
} }
return word };
} \ No newline at end of file
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论