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

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

上级 ba800b15
......@@ -265,12 +265,13 @@ const onHighlightedText = (text, nounList) => {
const key = `${searchInterval.start}-${searchInterval.end}`;
if (end === searchInterval.end && !pointAdded.has(key)) {
findWordMax.value++;
list.push({ point: true, class: "" });
list.push({ point: findWordMax.value, class: "" });
pointAdded.add(key);
break;
}
}
}
console.log('看看格式', list);
return list;
};
......
......@@ -19,7 +19,7 @@ const decreeRoutes = [
name: "Decree",
component: Decree,
meta: {
title: "科技政令概",
title: "科技政令概",
isShowHeader: true
}
},
......
......@@ -6,19 +6,19 @@
<div class="hard-num text-title-2-show">{{ organizationInfo.total }}</div>
<div style="width: 0px; flex: auto;"></div>
<div class="hard-input">
<el-input v-model="organizationInfo.keyWord" @keyup.enter="onAllOrganization()"
style="width:100%; height:100%;" :suffix-icon="Search" placeholder="搜索机构" />
<el-input v-model="organizationInfo.keyWord" @keyup.enter="onAllOrganization()" @clear="onAllOrganization()"
style="width:100%; height:100%;" :prefix-icon="Search" placeholder="搜索机构" clearable />
</div>
<div class="hard-time">
<el-select v-model="organizationInfo.isSort" @change="onAllOrganization()" placeholder="发布时间"
style="width:160px; margin-left:8px;">
<el-select v-model="organizationInfo.isSort" @change="onAllOrganization()" style="width:100%;">
<template #prefix>
<div class="icon1">
<img v-if="isSort" src="@/assets/icons/shengxu1.png" alt="" />
<img v-else src="@/assets/icons/jiangxu1.png" alt="" />
<img src="@/assets/icons/jiangxu1.png" alt="" />
<!-- <img src="@/assets/icons/shengxu1.png" alt="" /> -->
</div>
</template>
<el-option label="政令数量" :value="1" />
<el-option label="政令数据总量" :value="1" />
<el-option label="政令新增数量" :value="2" />
</el-select>
</div>
</div>
......@@ -30,13 +30,12 @@
<TimeTabPane @time-click="handleDateChange" activeTime="近一年" />
</div>
<div class="organization-list" ref="refOrganization" v-loading="organizationInfo.loading">
<div class="organization-item" v-for="(item, index) in organizationInfo.list" :key="index"
@click="handleToInstitution(item)">
<div class="organization-item" v-for="item in organizationInfo.list" :key="item.orgId">
<div class="item-left">
<img :src="item.orgImage || DefaultIcon2" alt="" />
</div>
<div class="item-right one-line-ellipsis">{{ item.orgName }}</div>
<div class="item-total">{{ item.total }}项</div>
<div class="item-right one-line-ellipsis text-click-hover" @click="handleToInstitution(item)">{{ item.orgName }}</div>
<div class="item-total text-click-hover" @click="handleToDataLibrary(item)">{{ item.total }}项</div>
<el-icon color="var(--color-primary-100)">
<ArrowRightBold />
</el-icon>
......@@ -50,17 +49,15 @@
</div>
</div>
<div class="back-bnt" @click="router.back()">
<el-icon>
<Back />
</el-icon>
<el-icon> <Back /> </el-icon>
<div style="margin-left: 6px;">返回</div>
</div>
</div>
</template>
<script setup name="index">
<script setup>
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 TimeTabPane from '@/components/base/TimeTabPane/index.vue';
......@@ -112,9 +109,7 @@ const handleToInstitution = item => {
window.sessionStorage.setItem("curTabName", item.orgName);
const curRoute = router.resolve({
path: "/institution",
query: {
id: item.orgId
}
query: { id: item.orgId }
});
window.open(curRoute.href, "_blank");
// router.push({
......@@ -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()
onMounted(() => {
// 根据元素的高度决定分页显示的机构数量
......@@ -196,15 +200,14 @@ onMounted(() => {
background-color: var(--el-fill-color-blank);
border-radius: var(--el-border-radius-base);
box-shadow: 0 0 0 1px var(--el-border-color) inset;
box-sizing: border-box;
margin-left: 20px;
width: 160px;
height: 32px;
}
.hard-time {
height: 42px;
padding: 5px 0;
height: 32px;
width: 160px;
margin-left: 8px;
.icon1 {
width: 11px;
......@@ -269,7 +272,6 @@ onMounted(() => {
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
align-items: center;
justify-content: center;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
position: relative;
......
......@@ -3,7 +3,7 @@
<div class="box1">
<AnalysisBox title="相关政令" :showAllBtn="false">
<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>
<div class="left-item" :class="{ 'item-active': false }" v-for="(item, index) in siderList" :key="index" @click="handleClickDecree(item)">
<div class="item-head">
......@@ -19,7 +19,7 @@
<div class="box2">
<AnalysisBox title="政令关系挖掘" :showAllBtn="false">
<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">
<GraphChart :nodes="graphData.nodes" :links="graphData.links" layoutType="force" @handleClickNode="handleClickNode" />
</div>
......
......@@ -2,7 +2,7 @@
<div class="layout-container">
<!-- 导航菜单 -->
<div class="layout-main">
<div class="header-main">
<div class="layout-head">
<div class="layout-main-header">
<div class="layout-main-header-container">
<div class="layout-main-header-left-box">
......@@ -65,7 +65,7 @@
</div>
</div>
</div>
<div class="layout-main-center">
<div class="layout-down">
<router-view />
</div>
</div>
......@@ -208,68 +208,7 @@ onMounted(() => {
height: 100%;
overflow: hidden;
overflow-y: auto;
.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;
}
}
}
}
background-color: white;
.layout-main {
width: 100%;
......@@ -277,10 +216,10 @@ onMounted(() => {
display: flex;
flex-direction: column;
.header-main {
.layout-head {
width: 100%;
border-bottom: 1px solid rgba(234, 236, 238, 1);
box-shadow: 0px 0px 20px 0px rgba(25, 69, 130, 0.1);
border-bottom: 1px solid rgb(234, 236, 238);
box-shadow: 0 0 20px #1945821a;
background: rgba(255, 255, 255, 1);
}
......@@ -288,7 +227,6 @@ onMounted(() => {
width: 1600px;
height: 137px;
margin: 0 auto;
background: rgba(255, 255, 255, 1);
display: flex;
justify-content: space-between;
position: sticky;
......@@ -526,10 +464,9 @@ onMounted(() => {
}
}
.layout-main-center {
.layout-down {
height: 20px;
flex: auto;
background-color: #f7f8f9;
}
}
}
......
<template>
<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
v-if="listData.length"
class="main-content-main"
......@@ -10,12 +10,8 @@
@mouseleave="handleMouseUp"
@mousemove="handleMouseMove"
>
<div
class="fishbone-container"
:style="{
transform: `translate(${translateX}px, ${translateY}px) scale(${scale})`,
transformOrigin: 'center center'
}"
<div class="fishbone-container"
:style="{ transform: `translate(${translateX}px, ${translateY}px) scale(${scale})` }"
>
<!-- 主轴上的标签 -->
<div class="main-line" :style="{ width: listData.length * 200 + 300 + 'px' }">
......@@ -152,18 +148,18 @@
</template>
<script setup name="ChartChain">
import { ref } from "vue";
import { onBeforeUnmount, ref, watch } from "vue";
import defaultIcon2 from "@/assets/icons/default-icon2.png";
import noticeIcon from "../assets/images/notice-icon.png";
const props = defineProps({
baseData: {
type: Object,
default: () => []
type: Array,
default: () => ([])
},
listData: {
type: Array,
default: () => []
default: () => ([])
}
});
......@@ -211,6 +207,15 @@ const handleMouseUp = () => {
};
// #endregion 移动功能处理
// 初始化布局
const watchInfo = watch(() => props.listData, val => {
scale.value = 1;
translateX.value = 0;
translateY.value = 0;
})
onBeforeUnmount(() => { watchInfo() });
// 奇数索引的数据组放在上方, 偶数索引的数据组放在下方
const onFilterData = num => {
return props.listData.filter((_, index) => index % 2 === num);
......@@ -247,9 +252,14 @@ const formatRate = (item, key) => {
align-items: center;
justify-content: center;
overflow: hidden;
-webkit-user-select: none; /* Safari/Chrome */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none; /* 标准语法 */
.fishbone-container {
position: relative;
transform-origin: center center;
.main-line {
height: 3px;
......
......@@ -16,7 +16,7 @@
</div>
<div class="data-title">实体名称</div>
<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>
<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)">
......@@ -81,7 +81,7 @@
</div>
<div class="graph-box" v-if="contentType==2">
<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>
</AnalysisBox>
......@@ -234,7 +234,6 @@ const onDecreeChainNodes = async (id) => {
}
})
fishbone.list = Object.values(obj);
console.log("fishbone.list:", fishbone.list);
fishbone.base = res.data.levelInfos.map((item, index) => {
return {...item, name: ['上游', '中游', '下游'][index]}
});
......@@ -448,10 +447,13 @@ onMounted(() => {
:deep(.header-icon) {
display: none;
}
:deep(.wrapper-header) {
padding-top: 8px;
}
.custom-title {
display: flex;
justify-content: space-between;
align-items: flex-end;
align-items: center;
width: 100%;
height: 100%;
padding: 0 20px;
......
......@@ -5,10 +5,8 @@
<AnalysisBox title="提出背景" :showAllBtn="false">
<template #header-btn>
<div class="header-btn-box">
<div class="btn" :class="{ btnActive: box1ActiveBtn === item }" v-for="(item, index) in box1BtnList"
:key="index" @click="handleClickBox1Btn(item)">
{{ item }}
</div>
<div class="btn" :class="{ btnActive: box1ActiveBtn === 1 }" @click="handleClickBox1Btn(1)">涉华背景</div>
<div class="btn" :class="{ btnActive: box1ActiveBtn === 2 }" @click="handleClickBox1Btn(2)">全部背景</div>
</div>
</template>
<div class="box1-container">
......@@ -17,9 +15,9 @@
<div class="box1-item" v-for="(item, index) in backgroundList" :key="index">
<div class="id">{{ index + 1 }}</div>
<div class="title text-align-justify">{{ item.content }}</div>
<div class="open">
<!-- <div class="open">
<img src="./assets/images/open-icon.png" alt="" />
</div>
</div> -->
</div>
</div>
<div class="box1-footer" v-if="backgroundListNum > 10">
......@@ -32,15 +30,15 @@
</div>
</AnalysisBox>
</div>
<div class="box2">
<div class="box2" v-loading="box2Params.loading">
<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="custom-collapse">
<el-collapse v-model="dependActive">
<el-collapse-item v-for="(item, index) in dependList" :key="item.billId" :name="item.billId">
<el-collapse v-model="box2Params.active">
<el-collapse-item v-for="(item, index) in box2Params.list" :key="item.billId" :name="item.billId">
<template #icon>
<el-icon v-if="dependActive.includes(item.billId)">
<el-icon v-if="box2Params.active.includes(item.billId)">
<ArrowDownBold />
</el-icon>
<el-icon v-else>
......@@ -92,7 +90,7 @@
</template>
<script setup>
import { ref, onMounted } from "vue";
import { ref, onMounted, reactive } from "vue";
import { useRoute } from "vue-router";
import { getDecreeBackground, getDecreeDepend, getDecreePrev } from "@/api/decree/background";
import router from "@/router";
......@@ -104,8 +102,7 @@ const route = useRoute();
const decreeId = ref(route.query.id);
// 提出背景
const box1BtnList = ref(["涉华背景", "全部背景"]);
const box1ActiveBtn = ref("涉华背景");
const box1ActiveBtn = ref(1);
const handleClickBox1Btn = btn => {
box1ActiveBtn.value = btn;
handleCurrentChange(1)
......@@ -126,7 +123,7 @@ const handleCurrentChange = page => {
};
const handleGetBackground = async () => {
const params = {
cRelated: box1ActiveBtn.value === "涉华背景" ? true : false,
cRelated: box1ActiveBtn.value === 1,
currentPage: currentPage.value - 1,
pageSize: 10,
id: decreeId.value
......@@ -144,7 +141,6 @@ const handleGetBackground = async () => {
} catch (error) {
backgroundListNum.value = 0;
backgroundList.value = [];
console.error("获取提出背景数据失败", error);
}
};
......@@ -167,7 +163,6 @@ const handleGetPrev = async () => {
}
} catch (error) {
prevList.value = [];
console.error("获取前序政令数据失败", error);
}
};
// 跳转行政机构主页
......@@ -205,22 +200,25 @@ const handleClickDecree = item => {
};
// 法律依据
const dependList = ref([]);
const dependActive = ref([]);
const box2Params = reactive({
loading: false,
active: [],
list: [],
})
const handleGetLaws = async () => {
box2Params.loading = true;
try {
const res = await getDecreeDepend({ id: decreeId.value });
console.log("法律依据", res);
if (res.code === 200 && res.data) {
dependList.value = res.data;
// dependActive.value = res.data.map(item => item.billId);
box2Params.list = res.data;
} else {
dependList.value = [];
box2Params.list = [];
}
} catch (error) {
dependList.value = [];
console.error("获取法律依据数据失败", error);
box2Params.list = [];
}
box2Params.loading = false;
};
// 跳转科技法案详情页
const handleClickBull = decree => {
......@@ -290,10 +288,11 @@ onMounted(() => {
}
.box1-main {
width: 1034px;
width: 100%;
padding: 0 6px;
.box1-item {
width: 1015px;
width: 100%;
min-height: 48px;
font-family: Microsoft YaHei;
font-size: var(--font-size-base);
......@@ -302,11 +301,10 @@ onMounted(() => {
background: rgba(255, 255, 255, 1);
display: flex;
align-items: center;
padding: 18px 0;
padding: 18px 16px;
.id {
margin-right: 16px;
margin-left: 15px;
width: 24px;
height: 24px;
text-align: center;
......@@ -357,9 +355,8 @@ onMounted(() => {
}
.box2 {
.box2-main {
padding: 16px 20px;
padding: 10px 24px 16px;
.custom-collapse {
padding-left: 32px;
......@@ -371,6 +368,8 @@ onMounted(() => {
:deep(.el-collapse-item__header) {
border-bottom: 1px solid rgba(234, 236, 238, 1);
min-height: 50px;
line-height: 50px;
}
:deep(.el-collapse-item__content) {
......@@ -384,18 +383,19 @@ onMounted(() => {
font-family: Microsoft YaHei;
font-size: var(--font-size-base);
position: absolute;
top: 12px;
top: 13px;
left: -32px;
width: 24px;
height: 24px;
text-align: center;
line-height: 24px;
text-align: center;
border-radius: 50%;
background: #e7f3ff;
color: #0a57a6;
}
.custom-collapse-name {
padding-left: 6px;
font-weight: 600;
font-size: 18px;
color: var(--el-collapse-header-text-color);
......
......@@ -70,7 +70,6 @@ onMounted(() => {
.decree-overview-wrap {
width: 100%;
overflow: hidden;
background: rgba(247, 248, 249, 1);
.main {
position: relative;
width: 1600px;
......
......@@ -145,7 +145,7 @@
<div class="box3-bottom-main">
<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">
<div class="timeline-content">{{ item.describe }}</div>
<div class="timeline-content text-align-justify">{{ item.describe }}</div>
</el-timeline-item>
</el-timeline>
</div>
......@@ -789,6 +789,12 @@ onMounted(() => {
font-size: 14px;
font-weight: 400;
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 @@
<DivideHeader id="position3" class="divide-header" :titleText="'数据总览'"></DivideHeader>
<div class="center-footer">
<div class="box5">
<OverviewNormalBox title="数量变化趋势">
<OverviewNormalBox title="数量变化趋势" width="auto" height="100%">
<template #header-icon>
<img style="width: 100%; height: 100%;" src="./assets/icons/icon2.svg" alt="" />
</template>
......@@ -97,7 +97,7 @@
<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>
<TipTab text="美对华发起调查案件数量变化趋势,数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" style="margin-top: 16px;" />
<TipTab text="数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" style="margin-top: 16px;" />
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="aiContent.content5" />
......@@ -106,7 +106,7 @@
</OverviewNormalBox>
</div>
<div class="box6">
<OverviewNormalBox title="领域分布情况" width="521px">
<OverviewNormalBox title="领域分布情况" width="auto" height="100%">
<template #header-icon>
<img style="width: 100%; height: 100%;" src="./assets/icons/icon3.svg" alt="" />
</template>
......@@ -122,7 +122,7 @@
<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>
<TipTab text="美对华发起调查案件领域分布情况,数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" ellipsis style="padding-right: 50px;" />
<TipTab text="数据来源:美国国际贸易委员会、商务部、贸易代表办公室官网" style="padding-right: 50px;" />
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="aiContent.content6" />
......@@ -133,7 +133,7 @@
</div>
<div class="center-footer1">
<div class="box7">
<OverviewNormalBox title="国家分布情况" width="1064px">
<OverviewNormalBox title="国家分布情况" width="auto" height="100%">
<template #header-icon>
<img style="width: 100%; height: 100%;" src="./assets/icons/icon4.svg" alt="" />
</template>
......@@ -154,7 +154,7 @@
<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>
<TipTab :text="`美发起调查案件的被调查国家分布情况,数据来源:${box7TipText}`" style="margin-top: 10px;" />
<TipTab :text="`数据来源:${box7TipText}`" style="margin-top: 10px;" />
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="aiContent.content7" />
......@@ -163,7 +163,7 @@
</OverviewNormalBox>
</div>
<div class="box8">
<OverviewNormalBox title="结果分布情况" width="521px">
<OverviewNormalBox title="结果分布情况" width="auto" height="100%">
<template #header-icon>
<img style="width: 100%; height: 100%" src="./assets/icons/icon5.svg" alt="" />
</template>
......@@ -179,7 +179,7 @@
<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>
<TipTab :text="`美发起调查案件的被调查国家分布情况,数据来源:${box8TipText}`" ellipsis style="padding-right: 50px;" />
<TipTab :text="`数据来源:${box8TipText}`" style="padding-right: 50px;" />
<div class="ai-pane">
<AiButton />
<AiPane :aiContent="aiContent.content8" />
......@@ -304,7 +304,7 @@ import { getDateBefore, getAIReport, getNearYearList } from "@/views/marketAcces
import router from "@/router";
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 getRadarChart from "./utils/radarChart";
import getBarChart from "./utils/barChart1";
......@@ -863,7 +863,7 @@ const handleGetBox8Data = async () => {
box8Data.value = []
aiContent.content8 = "";
}
nextTick(() => { createPieChart(box8Ref, box8Data.value, {labelType:1}) })
nextTick(() => { createPieChart(box8Ref, box8Data.value) })
};
// 资源库
......@@ -1814,15 +1814,16 @@ onMounted(async () => {
}
.center-footer {
margin-top: 21px;
margin: 21px auto 0;
height: 460px;
display: flex;
justify-content: center;
gap: 15px;
gap: 16px;
width: 1600px;
.box5 {
width: 1064px;
height: 460px;
width: 20px;
flex: auto;
height: 100%;
.box-header-right {
height: 48px;
......@@ -1865,8 +1866,9 @@ onMounted(async () => {
}
.box6 {
width: 521px;
height: 460px;
width: 20px;
flex: auto;
height: 100%;
.box-header-right {
height: 48px;
......@@ -1879,14 +1881,16 @@ onMounted(async () => {
}
.center-footer1 {
margin-top: 16px;
margin: 16px auto 0;
height: 460px;
display: flex;
justify-content: center;
gap: 15px;
gap: 16px;
width: 1600px;
.box7 {
width: 1064px;
height: 460px;
width: 20px;
flex: auto;
height: 100%;
.box-header-right {
height: 48px;
......@@ -1903,8 +1907,9 @@ onMounted(async () => {
}
.box8 {
width: 521px;
height: 460px;
width: 20px;
flex: auto;
height: 100%;
.box-header-right {
height: 48px;
......
import * as echarts from 'echarts'
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={}) => {
if (!chartDom.value) return;
......@@ -46,21 +30,21 @@ const createPieChart = (chartDom, data=[], option={}) => {
},
label: {
alignTo: 'edge',
formatter: (node) => formatLabel(node, option.labelType),
formatter: (node) => `{name|${node.name}}\n{time|${node.value}${ node.percent||0}%}`,
minMargin: 5,
edgeDistance: 10,
lineHeight: 22,
lineHeight: 26,
rich: {
name: {
color: 'rgba(59, 65, 75, 1)',
fontFamily: 'Microsoft YaHei',
fontFamily: 'Source Han Sans CN',
fontSize: 16,
fontWeight: 'bold',
padding: [10, 0, 10, 0]
},
time: {
color: 'rgba(95, 101, 108, 1)',
fontFamily: 'Microsoft YaHei',
fontFamily: 'Source Han Sans CN',
fontSize: 16,
padding: [10, 0, 10, 0]
}
......
......@@ -61,51 +61,51 @@ export const getNearYearList = (num=6) => {
* AI智能总结
* @param data 需要分析的数据
*/
export const getAIReport = async (data:any) => {
let word = ""
export const getAIReport = async (data: any, timeoutMs: number = 10000): Promise<string> => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
// 👇 新增:超时 + 终止请求(只加这一段)
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10*1000); // 10秒超时
try {
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
});
try {
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(timeoutId);
clearTimeout(timeout); // 👇 新增:请求成功清除定时器
if (!res.ok) throw new Error(`HTTP 错误 ${res.status}`);
const reader = res.body.getReader();
const decoder = new TextDecoder();
if (!res.ok) throw new Error(`HTTP ${res.status}`);
let buffer = '';
let summarize = '';
const reader = res.body.getReader();
const decoder = new TextDecoder();
let result = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
// 添加读取超时
const readTimeout = setTimeout(() => {
reader.cancel();
}, timeoutMs);
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.startsWith('data: ')) {
const content = line.substring(6);
const textMatch = content.match(/"解读":\s*"([^"]*)"/);
if (textMatch && textMatch[1]) summarize = textMatch[1];
}
}
}
word = summarize
} catch (err) {
word = "系统异常,生成失败";
}
return word
}
\ No newline at end of file
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
const match = chunk.match(/"解读":\s*"([^"]*)"/);
if (match?.[1]) {
result = match[1];
break; // 获取到结果立即结束
}
}
} finally {
clearTimeout(readTimeout);
reader.cancel(); // 确保连接关闭
}
return result || "未获取到解读内容";
} catch (err) {
return "系统异常,生成失败";
}
};
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论