提交 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;
......
...@@ -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;
} }
} }
} }
......
...@@ -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,51 +61,51 @@ export const getNearYearList = (num=6) => { ...@@ -61,51 +61,51 @@ 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 timeoutId = setTimeout(() => controller.abort(), timeoutMs);
// 👇 新增:超时 + 终止请求(只加这一段) try {
const controller = new AbortController(); const res = await fetch('/aiAnalysis/chart_interpretation', {
const timeout = setTimeout(() => controller.abort(), 10*1000); // 10秒超时 method: 'POST',
headers: {
"X-API-Key": "aircasKEY19491001",
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: JSON.stringify(data) }),
signal: controller.signal
});
try { clearTimeout(timeoutId);
const res = await fetch('/aiAnalysis/chart_interpretation', {
method: 'POST',
headers: {
"X-API-Key": "aircasKEY19491001",
'Content-Type': 'application/json',
},
body: JSON.stringify({text: JSON.stringify(data)}),
signal: controller.signal // 👇 新增:绑定中断信号
});
clearTimeout(timeout); // 👇 新增:请求成功清除定时器 if (!res.ok) throw new Error(`HTTP ${res.status}`);
if (!res.ok) throw new Error(`HTTP 错误 ${res.status}`);
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = ''; const reader = res.body.getReader();
let summarize = ''; const decoder = new TextDecoder();
let result = '';
while (true) { // 添加读取超时
const { done, value } = await reader.read(); const readTimeout = setTimeout(() => {
if (done) break; reader.cancel();
}, timeoutMs);
buffer += decoder.decode(value, { stream: true }); try {
const lines = buffer.split('\n'); while (true) {
buffer = lines.pop() || ''; const { done, value } = await reader.read();
if (done) break;
for (const line of lines) { const chunk = decoder.decode(value, { stream: true });
if (line.startsWith('data: ')) { const match = chunk.match(/"解读":\s*"([^"]*)"/);
const content = line.substring(6); if (match?.[1]) {
const textMatch = content.match(/"解读":\s*"([^"]*)"/); result = match[1];
if (textMatch && textMatch[1]) summarize = textMatch[1]; break; // 获取到结果立即结束
} }
} }
} } finally {
word = summarize clearTimeout(readTimeout);
} catch (err) { reader.cancel(); // 确保连接关闭
word = "系统异常,生成失败"; }
} return result || "未获取到解读内容";
return word } catch (err) {
} return "系统异常,生成失败";
\ No newline at end of file }
};
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论