提交 a71756d8 authored 作者: 张伊明's avatar 张伊明

feat 法案首页新增loading,更改法案阶段字典

上级 ca4247e0
流水线 #243 已通过 于阶段
in 1 分 31 秒
...@@ -143,6 +143,7 @@ export function getChartAnalysis(data, options = {}) { ...@@ -143,6 +143,7 @@ export function getChartAnalysis(data, options = {}) {
: typeof options?.onInterpretationDelta === "function" : typeof options?.onInterpretationDelta === "function"
? options.onInterpretationDelta ? options.onInterpretationDelta
: null; : null;
const externalSignal = options?.signal;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let buffer = ""; let buffer = "";
let latestInterpretation = ""; let latestInterpretation = "";
...@@ -150,16 +151,32 @@ export function getChartAnalysis(data, options = {}) { ...@@ -150,16 +151,32 @@ export function getChartAnalysis(data, options = {}) {
let lastStreamedInterpretationLen = 0; let lastStreamedInterpretationLen = 0;
let settled = false; let settled = false;
const abortController = new AbortController(); const abortController = new AbortController();
const externalAbortHandler = () => {
abortController.abort();
};
if (externalSignal) {
if (externalSignal.aborted) {
abortController.abort();
} else {
externalSignal.addEventListener("abort", externalAbortHandler, { once: true });
}
}
const safeResolve = value => { const safeResolve = value => {
if (settled) return; if (settled) return;
settled = true; settled = true;
if (externalSignal) {
externalSignal.removeEventListener("abort", externalAbortHandler);
}
resolve(value); resolve(value);
}; };
const safeReject = err => { const safeReject = err => {
if (settled) return; if (settled) return;
settled = true; settled = true;
if (externalSignal) {
externalSignal.removeEventListener("abort", externalAbortHandler);
}
reject(err); reject(err);
}; };
......
...@@ -107,11 +107,12 @@ export function getBillPersonAnalyzeDy(params) { ...@@ -107,11 +107,12 @@ export function getBillPersonAnalyzeDy(params) {
* @param {id} * @param {id}
* @header token * @header token
*/ */
export function getBillContentId(params) { export function getBillContentId(params, config = {}) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/billInfoBean/contentId/${params.id}`, url: `/api/billInfoBean/contentId/${params.id}`,
params, params,
signal: config.signal
}) })
} }
...@@ -120,11 +121,12 @@ export function getBillContentId(params) { ...@@ -120,11 +121,12 @@ export function getBillContentId(params) {
* @param {billId,id,cRelated,currentPage,pageSize,domainNameList,measuresNameList,content} * @param {billId,id,cRelated,currentPage,pageSize,domainNameList,measuresNameList,content}
* @header token * @header token
*/ */
export function getBillContentTk(params) { export function getBillContentTk(params, config = {}) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/billInfoBean/content/tk/${params.billId}/${params.id}`, url: `/api/billInfoBean/content/tk/${params.billId}/${params.id}`,
params, params,
signal: config.signal
}) })
} }
...@@ -133,11 +135,12 @@ export function getBillContentTk(params) { ...@@ -133,11 +135,12 @@ export function getBillContentTk(params) {
* @param {billId,versionId,cRelated} * @param {billId,versionId,cRelated}
* @header token * @header token
*/ */
export function getBillContentXzfs(params) { export function getBillContentXzfs(params, config = {}) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/billInfoBean/content/xzfs/${params.billId}/${params.versionId}`, url: `/api/billInfoBean/content/xzfs/${params.billId}/${params.versionId}`,
params, params,
signal: config.signal
}) })
} }
...@@ -146,11 +149,12 @@ export function getBillContentXzfs(params) { ...@@ -146,11 +149,12 @@ export function getBillContentXzfs(params) {
* @param {billId,versionId,cRelated} * @param {billId,versionId,cRelated}
* @header token * @header token
*/ */
export function getBillHyly(params) { export function getBillHyly(params, config = {}) {
return request({ return request({
method: 'GET', method: 'GET',
url: `/api/billInfoBean/content/hyly/${params.billId}/${params.versionId}`, url: `/api/billInfoBean/content/hyly/${params.billId}/${params.versionId}`,
params, params,
signal: config.signal
}) })
} }
......
...@@ -3,8 +3,14 @@ import request from "@/api/request.js"; ...@@ -3,8 +3,14 @@ import request from "@/api/request.js";
// 涉华法案领域分布 // 涉华法案领域分布
/** /**
* @param {Object} params * @param {Object} params
* @param {string} params.year - 年份 * @param {string} params.year - 年份(2022-2026)
* @param {string} [params.status] - 状态:提出法案/通过法案 * @param {string} [params.status] - 法案状态:
* - 提案
* - 众议院通过
* - 参议院通过
* - 分歧已解决
* - 呈交总统
* - 完成立法
*/ */
export function getBillIndustry(params) { export function getBillIndustry(params) {
return request({ return request({
......
...@@ -144,7 +144,7 @@ ...@@ -144,7 +144,7 @@
</el-select> </el-select>
</template> </template>
<div class="overview-card-body box5-main"> <div class="overview-card-body box5-main">
<div class="overview-chart-wrap" :class="{ 'is-empty': !box5HasData }"> <div class="overview-chart-wrap" v-loading="chartLoading.box5" :class="{ 'is-empty': !box5HasData }">
<el-empty v-if="!box5HasData" description="暂无数据" :image-size="100" /> <el-empty v-if="!box5HasData" description="暂无数据" :image-size="100" />
<div v-else id="box5Chart" class="overview-chart"></div> <div v-else id="box5Chart" class="overview-chart"></div>
</div> </div>
...@@ -169,7 +169,7 @@ ...@@ -169,7 +169,7 @@
</el-select> </el-select>
</template> </template>
<div class="overview-card-body box6-main"> <div class="overview-card-body box6-main">
<div class="overview-chart-wrap" :class="{ 'is-empty': !box9HasData }"> <div class="overview-chart-wrap" v-loading="chartLoading.box6" :class="{ 'is-empty': !box9HasData }">
<el-empty v-if="!box9HasData" description="暂无数据" :image-size="100" /> <el-empty v-if="!box9HasData" description="暂无数据" :image-size="100" />
<div v-else id="box9Chart" class="overview-chart"></div> <div v-else id="box9Chart" class="overview-chart"></div>
</div> </div>
...@@ -191,7 +191,7 @@ ...@@ -191,7 +191,7 @@
</el-select> </el-select>
</template> </template>
<div class="overview-card-body box7-main"> <div class="overview-card-body box7-main">
<div class="overview-chart-wrap" :class="{ 'is-empty': !box7HasData }"> <div class="overview-chart-wrap" v-loading="chartLoading.box7" :class="{ 'is-empty': !box7HasData }">
<el-empty v-if="!box7HasData" description="暂无数据" :image-size="100" /> <el-empty v-if="!box7HasData" description="暂无数据" :image-size="100" />
<div v-else id="box7Chart" class="overview-chart"></div> <div v-else id="box7Chart" class="overview-chart"></div>
</div> </div>
...@@ -211,10 +211,10 @@ ...@@ -211,10 +211,10 @@
</el-select> </el-select>
</template> </template>
<div class="overview-card-body box8-main"> <div class="overview-card-body box8-main">
<div class="overview-chart-wrap" :class="{ 'is-empty': !box8HasData }"> <div class="overview-chart-wrap" v-loading="chartLoading.box8" :class="{ 'is-empty': !box8HasData }">
<el-empty v-if="!box8HasData" description="暂无数据" :image-size="100" /> <el-empty v-if="!box8HasData" description="暂无数据" :image-size="100" />
<template v-else> <template v-else>
<div class="box8-desc">通过涉华法案{{ box8Summary }}</div> <div class="box8-desc">完成立法涉华法案{{ box8Summary }}</div>
<div id="box8Chart" class="overview-chart box8-chart"></div> <div id="box8Chart" class="overview-chart box8-chart"></div>
</template> </template>
</div> </div>
...@@ -229,7 +229,7 @@ ...@@ -229,7 +229,7 @@
</OverviewCard> </OverviewCard>
<OverviewCard class="overview-card--single box9" title="关键条款词云" :icon="box7HeaderIcon"> <OverviewCard class="overview-card--single box9" title="关键条款词云" :icon="box7HeaderIcon">
<div class="overview-card-body box9-main"> <div class="overview-card-body box9-main">
<div class="overview-chart-wrap"> <div class="overview-chart-wrap" v-loading="chartLoading.box9">
<el-empty v-if="!wordCloudHasData" description="暂无数据" :image-size="100" /> <el-empty v-if="!wordCloudHasData" description="暂无数据" :image-size="100" />
<WordCloundChart v-else class="overview-chart" width="100%" height="100%" :data="wordCloudData" /> <WordCloundChart v-else class="overview-chart" width="100%" height="100%" :data="wordCloudData" />
</div> </div>
...@@ -512,6 +512,14 @@ const aiPaneLoading = ref({ ...@@ -512,6 +512,14 @@ const aiPaneLoading = ref({
box9: false box9: false
}); });
const chartLoading = ref({
box5: false,
box6: false,
box7: false,
box8: false,
box9: false
});
const gotoNewsDetail = useGotoNewsDetail(); const gotoNewsDetail = useGotoNewsDetail();
const handleClickNewsDetail = news => { const handleClickNewsDetail = news => {
const newsId = news?.newsId || news?.id; const newsId = news?.newsId || news?.id;
...@@ -767,7 +775,7 @@ const box5Data = ref({ ...@@ -767,7 +775,7 @@ const box5Data = ref({
value: [145, 52, 84, 99, 71, 96, 128, 144, 140, 168, 188, 172] value: [145, 52, 84, 99, 71, 96, 128, 144, 140, 168, 188, 172]
}, },
{ {
name: "通过法案", name: "完成立法",
value: [6, 3, 4, 6, 11, 5, 2, 14, 16, 27, 28, 44] value: [6, 3, 4, 6, 11, 5, 2, 14, 16, 27, 28, 44]
}, },
{ {
...@@ -779,13 +787,14 @@ const box5Data = ref({ ...@@ -779,13 +787,14 @@ const box5Data = ref({
value: [] value: []
}, },
{ {
name: "双院通过", name: "解决分歧",
value: [] value: []
} }
] ]
}); });
const box5HasData = ref(true); const box5HasData = ref(true);
const handleGetBillCount = async () => { const handleGetBillCount = async () => {
chartLoading.value = { ...chartLoading.value, box5: true };
try { try {
const params = { const params = {
dateDesc: box5ProposalTime.value dateDesc: box5ProposalTime.value
...@@ -806,7 +815,7 @@ const handleGetBillCount = async () => { ...@@ -806,7 +815,7 @@ const handleGetBillCount = async () => {
value: sortedData.map(item => item.proposedCount) value: sortedData.map(item => item.proposedCount)
}, },
{ {
name: "通过法案", name: "完成立法",
value: sortedData.map(item => item.passCount) value: sortedData.map(item => item.passCount)
}, },
{ {
...@@ -818,7 +827,7 @@ const handleGetBillCount = async () => { ...@@ -818,7 +827,7 @@ const handleGetBillCount = async () => {
value: sortedData.map(item => item.senateCount) value: sortedData.map(item => item.senateCount)
}, },
{ {
name: "双院通过", name: "解决分歧",
value: sortedData.map(item => item.hscount) value: sortedData.map(item => item.hscount)
} }
], ],
...@@ -831,10 +840,10 @@ const handleGetBillCount = async () => { ...@@ -831,10 +840,10 @@ const handleGetBillCount = async () => {
title: [], title: [],
data: [ data: [
{ name: "提出法案", value: [] }, { name: "提出法案", value: [] },
{ name: "通过法案", value: [] }, { name: "完成立法", value: [] },
{ name: "众议院通过", value: [] }, { name: "众议院通过", value: [] },
{ name: "参议院通过", value: [] }, { name: "参议院通过", value: [] },
{ name: "双院通过", value: [] } { name: "解决分歧", value: [] }
], ],
percent: [] percent: []
}; };
...@@ -847,13 +856,15 @@ const handleGetBillCount = async () => { ...@@ -847,13 +856,15 @@ const handleGetBillCount = async () => {
title: [], title: [],
data: [ data: [
{ name: "提出法案", value: [] }, { name: "提出法案", value: [] },
{ name: "通过法案", value: [] }, { name: "完成立法", value: [] },
{ name: "众议院通过", value: [] }, { name: "众议院通过", value: [] },
{ name: "参议院通过", value: [] }, { name: "参议院通过", value: [] },
{ name: "双院通过", value: [] } { name: "解决分歧", value: [] }
], ],
percent: [] percent: []
}; };
} finally {
chartLoading.value = { ...chartLoading.value, box5: false };
} }
}; };
...@@ -893,6 +904,7 @@ const handleBox5Change = () => { ...@@ -893,6 +904,7 @@ const handleBox5Change = () => {
const box7HasData = ref(true); const box7HasData = ref(true);
const box7AiData = ref({ inner: [], outer: [] }); const box7AiData = ref({ inner: [], outer: [] });
const handleBox7Data = async () => { const handleBox7Data = async () => {
chartLoading.value = { ...chartLoading.value, box7: true };
try { try {
const res = await getBillPostOrg({ year: box7selectetedTime.value }); const res = await getBillPostOrg({ year: box7selectetedTime.value });
console.log("法案提出部门", res); console.log("法案提出部门", res);
...@@ -946,6 +958,8 @@ const handleBox7Data = async () => { ...@@ -946,6 +958,8 @@ const handleBox7Data = async () => {
console.error("获取法案提出部门数据失败", error); console.error("获取法案提出部门数据失败", error);
box7HasData.value = false; box7HasData.value = false;
box7AiData.value = { inner: [], outer: [] }; box7AiData.value = { inner: [], outer: [] };
} finally {
chartLoading.value = { ...chartLoading.value, box7: false };
} }
}; };
...@@ -972,6 +986,7 @@ const handleToSocialDetail = item => { ...@@ -972,6 +986,7 @@ const handleToSocialDetail = item => {
const wordCloudData = ref([]); const wordCloudData = ref([]);
const wordCloudHasData = computed(() => Array.isArray(wordCloudData.value) && wordCloudData.value.length > 0); const wordCloudHasData = computed(() => Array.isArray(wordCloudData.value) && wordCloudData.value.length > 0);
const handleGetKeyTK = async () => { const handleGetKeyTK = async () => {
chartLoading.value = { ...chartLoading.value, box9: true };
try { try {
const res = await getBillOverviewKeyTK(); const res = await getBillOverviewKeyTK();
console.log("关键条款", res); console.log("关键条款", res);
...@@ -989,6 +1004,8 @@ const handleGetKeyTK = async () => { ...@@ -989,6 +1004,8 @@ const handleGetKeyTK = async () => {
} }
} catch (error) { } catch (error) {
console.error("获取关键条款error", error); console.error("获取关键条款error", error);
} finally {
chartLoading.value = { ...chartLoading.value, box9: false };
} }
}; };
const handleBox6 = async () => { const handleBox6 = async () => {
...@@ -998,10 +1015,15 @@ const handleBox6 = async () => { ...@@ -998,10 +1015,15 @@ const handleBox6 = async () => {
// 涉华领域分布 // 涉华领域分布
const box9ChartData = ref([]); const box9ChartData = ref([]);
const box9selectetedTime = ref("2025"); const box9selectetedTime = ref("2025");
const box9LegislativeStatus = ref("提出法案"); // 立法状态下拉:提出法案、众议院通过、参议院通过、解决分歧、完成立法
// v-model 存储的是接口需要的 status 值
const box9LegislativeStatus = ref("提案");
const box9LegislativeStatusList = ref([ const box9LegislativeStatusList = ref([
{ label: "提出法案", value: "提出法案" }, { label: "提出法案", value: "提案" },
{ label: "通过法案", value: "通过法案" } { label: "众议院通过", value: "众议院通过" },
{ label: "参议院通过", value: "参议院通过" },
{ label: "解决分歧", value: "分歧已解决" },
{ label: "完成立法", value: "完成立法" }
]); ]);
const box9YearList = ref([ const box9YearList = ref([
{ {
...@@ -1028,6 +1050,7 @@ const box9YearList = ref([ ...@@ -1028,6 +1050,7 @@ const box9YearList = ref([
const box9HasData = ref(true); const box9HasData = ref(true);
let box9ChartInstance = null; let box9ChartInstance = null;
const getBox9Data = async () => { const getBox9Data = async () => {
chartLoading.value = { ...chartLoading.value, box6: true };
const params = { const params = {
year: box9selectetedTime.value, year: box9selectetedTime.value,
status: box9LegislativeStatus.value status: box9LegislativeStatus.value
...@@ -1045,6 +1068,8 @@ const getBox9Data = async () => { ...@@ -1045,6 +1068,8 @@ const getBox9Data = async () => {
} catch (error) { } catch (error) {
box9HasData.value = false; box9HasData.value = false;
box9ChartData.value = []; box9ChartData.value = [];
} finally {
chartLoading.value = { ...chartLoading.value, box6: false };
} }
}; };
const handleBox9Data = async () => { const handleBox9Data = async () => {
...@@ -1061,11 +1086,15 @@ const handleBox9Data = async () => { ...@@ -1061,11 +1086,15 @@ const handleBox9Data = async () => {
null, null,
{ showCount: false } { showCount: false }
); );
// 记录埋点时,将当前选中的立法状态映射为序号(0-4)
const selectedIndex = box9LegislativeStatusList.value.findIndex(
item => item.value === box9LegislativeStatus.value
);
const selectParam = { const selectParam = {
moduleType: '国会法案', moduleType: '国会法案',
key: '领域', key: '领域',
selectedDate: box9selectetedTime.value, selectedDate: box9selectetedTime.value,
selectedStatus: box9LegislativeStatus.value === '提出法案' ? 0 : 1, selectedStatus: selectedIndex,
isInvolveCn: 1 isInvolveCn: 1
} }
box9ChartInstance = setChart(box9Chart, "box9Chart", true, selectParam); box9ChartInstance = setChart(box9Chart, "box9Chart", true, selectParam);
...@@ -1088,14 +1117,13 @@ const box8StageList = ref([]); ...@@ -1088,14 +1117,13 @@ const box8StageList = ref([]);
const box8MockDataByYear = { const box8MockDataByYear = {
"2025": { "2025": {
passCount: 19, passCount: 19,
// 从上到下顺序:提出法案、众议院通过、参议院通过、解决分歧、完成立法
stages: [ stages: [
{ name: "已提案", count: 24 }, { name: "提出法案", count: 24 },
{ name: "众议院通过", count: 20 }, { name: "众议院通过", count: 20 },
{ name: "众议院不通过", count: 25 },
{ name: "解决分歧", count: 23 },
{ name: "参议院通过", count: 26 }, { name: "参议院通过", count: 26 },
{ name: "总统否决", count: 48 }, { name: "解决分歧", count: 23 },
{ name: "立法", count: 19 } { name: "完成立法", count: 19 }
] ]
} }
}; };
...@@ -1219,15 +1247,15 @@ const getBox8ChartOption = stageList => { ...@@ -1219,15 +1247,15 @@ const getBox8ChartOption = stageList => {
}; };
const handleBox8Data = async () => { const handleBox8Data = async () => {
const stageOrder = ["提案", "众议院通过", "众议院不通过", "分歧已解决", "参议院通过", "总统否决或未签署", "完成立法"]; chartLoading.value = { ...chartLoading.value, box8: true };
// 进展分布显示顺序:提出法案(对应进度“提案”)、众议院通过、参议院通过、分歧已解决(解决分歧)、完成立法
const stageOrder = ["提案", "众议院通过", "参议院通过", "分歧已解决", "完成立法"];
const stageNameMap = { const stageNameMap = {
提案: "已提案", 提案: "提出法案",
众议院通过: "众议院通过", 众议院通过: "众议院通过",
众议院不通过: "众议院不通过",
分歧已解决: "解决分歧",
参议院通过: "参议院通过", 参议院通过: "参议院通过",
"总统否决或未签署": "总统否决", 分歧已解决: "解决分歧",
完成立法: "立法" 完成立法: "完成立法"
}; };
try { try {
...@@ -1286,6 +1314,8 @@ const handleBox8Data = async () => { ...@@ -1286,6 +1314,8 @@ const handleBox8Data = async () => {
box8StageList.value = []; box8StageList.value = [];
setChart({}, "box8Chart", true, selectParam); setChart({}, "box8Chart", true, selectParam);
} }
} finally {
chartLoading.value = { ...chartLoading.value, box8: false };
} }
}; };
......
...@@ -49,7 +49,8 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, ...@@ -49,7 +49,8 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
containLabel: true containLabel: true
}, },
legend: { legend: {
data: ['提出法案', '通过法案', '众议院通过', '参议院通过', '双院通过'], // 图例顺序:提出法案、众议院通过、参议院通过、解决分歧、完成立法
data: ['提出法案', '众议院通过', '参议院通过', '解决分歧', '完成立法'],
show: true, show: true,
top: 10, top: 10,
icon: 'circle', icon: 'circle',
...@@ -126,7 +127,8 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, ...@@ -126,7 +127,8 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
data: proposedData data: proposedData
}, },
{ {
name: '通过法案', // 众议院通过
name: '众议院通过',
type: 'line', type: 'line',
smooth: true, smooth: true,
symbol: 'emptyCircle', symbol: 'emptyCircle',
...@@ -137,10 +139,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, ...@@ -137,10 +139,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle: { itemStyle: {
color: lineColors[1] color: lineColors[1]
}, },
data: passData data: houseData
}, },
{ {
name: '众议院通过', // 参议院通过
name: '参议院通过',
type: 'line', type: 'line',
smooth: true, smooth: true,
symbol: 'emptyCircle', symbol: 'emptyCircle',
...@@ -151,10 +154,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, ...@@ -151,10 +154,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle: { itemStyle: {
color: lineColors[2] color: lineColors[2]
}, },
data: houseData data: senateData
}, },
{ {
name: '参议院通过', // 解决分歧
name: '解决分歧',
type: 'line', type: 'line',
smooth: true, smooth: true,
symbol: 'emptyCircle', symbol: 'emptyCircle',
...@@ -165,10 +169,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, ...@@ -165,10 +169,11 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle: { itemStyle: {
color: lineColors[3] color: lineColors[3]
}, },
data: senateData data: hsData
}, },
{ {
name: '双院通过', // 完成立法
name: '完成立法',
type: 'line', type: 'line',
smooth: true, smooth: true,
symbol: 'emptyCircle', symbol: 'emptyCircle',
...@@ -179,7 +184,7 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData, ...@@ -179,7 +184,7 @@ const getMultiLineChart = (dataX, proposedData, passData, houseData, senateData,
itemStyle: { itemStyle: {
color: lineColors[4] color: lineColors[4]
}, },
data: hsData data: passData
} }
] ]
} }
......
...@@ -27,17 +27,6 @@ ...@@ -27,17 +27,6 @@
</div> </div>
<div class="left-box-bottom" v-if="showTabs"> <div class="left-box-bottom" v-if="showTabs">
<template v-if="isLoading">
<div class="left-box-bottom-item is-skeleton" v-for="n in 4" :key="n">
<div class="icon">
<el-skeleton-item class="skeleton-tab-icon" variant="text" />
</div>
<div class="name">
<el-skeleton-item class="skeleton-tab-text" variant="text" />
</div>
</div>
</template>
<template v-else>
<div class="left-box-bottom-item" <div class="left-box-bottom-item"
:class="{ leftBoxBottomItemActive: activeTitle === item.name }" v-for="item in tabs" :class="{ leftBoxBottomItemActive: activeTitle === item.name }" v-for="item in tabs"
:key="item.path" @click="emit('tab-click', item)"> :key="item.path" @click="emit('tab-click', item)">
...@@ -49,7 +38,6 @@ ...@@ -49,7 +38,6 @@
{{ item.name }} {{ item.name }}
</div> </div>
</div> </div>
</template>
</div> </div>
</div> </div>
...@@ -73,17 +61,6 @@ ...@@ -73,17 +61,6 @@
</div> </div>
<div class="right-box-bottom" v-if="showActions"> <div class="right-box-bottom" v-if="showActions">
<template v-if="isLoading">
<div class="btn3 is-skeleton">
<div class="icon">
<el-skeleton-item class="skeleton-action-icon" variant="text" />
</div>
<div class="text">
<el-skeleton-item class="skeleton-action-text" variant="text" />
</div>
</div>
</template>
<template v-else>
<div class="btn2" @click="emit('open-analysis', 'forsee')"> <div class="btn2" @click="emit('open-analysis', 'forsee')">
<div class="icon"> <div class="icon">
<img :src="btnIconForsee" alt="" /> <img :src="btnIconForsee" alt="" />
...@@ -96,7 +73,6 @@ ...@@ -96,7 +73,6 @@
</div> </div>
<div class="text">{{ "分析报告" }}</div> <div class="text">{{ "分析报告" }}</div>
</div> </div>
</template>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -150,8 +150,8 @@ ...@@ -150,8 +150,8 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, computed, watch } from "vue"; import { ref, onMounted, onBeforeUnmount, computed, watch } from "vue";
import { useRoute } from "vue-router"; import { useRoute, onBeforeRouteLeave } from "vue-router";
import * as echarts from "echarts"; import * as echarts from "echarts";
import { Search } from "@element-plus/icons-vue"; import { Search } from "@element-plus/icons-vue";
import getPieChart from "./utils/piechart"; import getPieChart from "./utils/piechart";
...@@ -165,6 +165,31 @@ import { extractTextEntity } from "@/api/intelligent/index"; ...@@ -165,6 +165,31 @@ import { extractTextEntity } from "@/api/intelligent/index";
const route = useRoute(); const route = useRoute();
const pageAbortController = new AbortController();
const isRequestCanceled = error => {
return (
error?.code === "ERR_CANCELED" ||
error?.name === "CanceledError" ||
error?.name === "AbortError" ||
(typeof error?.message === "string" && /canceled|aborted/i.test(error.message))
);
};
const getPageSignal = () => pageAbortController.signal;
const stopCurrentPageRequests = () => {
pageAbortController.abort();
// 让旧请求回调全部失效,避免离开页面后回写状态
tkRequestToken.value += 1;
xzfsRequestToken.value += 1;
hylyRequestToken.value += 1;
entityRequestToken.value += 1;
termsLoading.value = false;
limitLoading.value = false;
domainLoading.value = false;
aiPaneLoading.value = { domain: false, limit: false };
};
const curBill = ref(""); const curBill = ref("");
const curBillId = ref(null); const curBillId = ref(null);
...@@ -294,7 +319,7 @@ const ensureEntitiesForTerms = async terms => { ...@@ -294,7 +319,7 @@ const ensureEntitiesForTerms = async terms => {
try { try {
const results = await Promise.all( const results = await Promise.all(
tasks.map(async item => { tasks.map(async item => {
const res = await extractTextEntity(item.text); const res = await extractTextEntity(item.text, { signal: getPageSignal() });
const entities = normalizeEntities(res?.result ?? res?.data?.result ?? res?.data ?? res); const entities = normalizeEntities(res?.result ?? res?.data?.result ?? res?.data ?? res);
return { key: item.key, entities }; return { key: item.key, entities };
}) })
...@@ -434,6 +459,7 @@ const requestAiPaneContent = async key => { ...@@ -434,6 +459,7 @@ const requestAiPaneContent = async key => {
const res = await getChartAnalysis( const res = await getChartAnalysis(
{ text: JSON.stringify(payload) }, { text: JSON.stringify(payload) },
{ {
signal: getPageSignal(),
onChunk: chunk => { onChunk: chunk => {
const current = overviewAiContent.value[key]; const current = overviewAiContent.value[key];
const base = current === "智能总结生成中..." ? "" : current; const base = current === "智能总结生成中..." ? "" : current;
...@@ -455,6 +481,7 @@ const requestAiPaneContent = async key => { ...@@ -455,6 +481,7 @@ const requestAiPaneContent = async key => {
} }
aiPaneFetched.value = { ...aiPaneFetched.value, [key]: true }; aiPaneFetched.value = { ...aiPaneFetched.value, [key]: true };
} catch (error) { } catch (error) {
if (isRequestCanceled(error)) return;
console.error("获取图表解读失败", error); console.error("获取图表解读失败", error);
overviewAiContent.value = { ...overviewAiContent.value, [key]: "智能总结生成失败" }; overviewAiContent.value = { ...overviewAiContent.value, [key]: "智能总结生成失败" };
} finally { } finally {
...@@ -518,7 +545,7 @@ const handleGetBillList = async () => { ...@@ -518,7 +545,7 @@ const handleGetBillList = async () => {
id: route.query.billId id: route.query.billId
}; };
try { try {
const res = await getBillContentId(params); const res = await getBillContentId(params, { signal: getPageSignal() });
console.log("法案id列表", res); console.log("法案id列表", res);
const rawList = Array.isArray(res?.data) ? res.data : []; const rawList = Array.isArray(res?.data) ? res.data : [];
const seen = new Set(); const seen = new Set();
...@@ -579,7 +606,7 @@ const handleGetBillContentTk = async cRelated => { ...@@ -579,7 +606,7 @@ const handleGetBillContentTk = async cRelated => {
params.content = searchKeyword.value.trim(); params.content = searchKeyword.value.trim();
} }
try { try {
const res = await getBillContentTk(params); const res = await getBillContentTk(params, { signal: getPageSignal() });
if (currentToken !== tkRequestToken.value) { if (currentToken !== tkRequestToken.value) {
return; return;
} }
...@@ -627,6 +654,9 @@ const handleGetBillContentTk = async cRelated => { ...@@ -627,6 +654,9 @@ const handleGetBillContentTk = async cRelated => {
total.value = 0; total.value = 0;
} }
} catch (error) { } catch (error) {
if (isRequestCanceled(error)) {
return;
}
if (currentToken !== tkRequestToken.value) { if (currentToken !== tkRequestToken.value) {
return; return;
} }
...@@ -652,7 +682,7 @@ const handleGetBillContentXzfs = async () => { ...@@ -652,7 +682,7 @@ const handleGetBillContentXzfs = async () => {
}; };
try { try {
const res = await getBillContentXzfs(params); const res = await getBillContentXzfs(params, { signal: getPageSignal() });
if (currentToken !== xzfsRequestToken.value) { if (currentToken !== xzfsRequestToken.value) {
return; return;
} }
...@@ -679,6 +709,9 @@ const handleGetBillContentXzfs = async () => { ...@@ -679,6 +709,9 @@ const handleGetBillContentXzfs = async () => {
let chart1 = getPieChart(chart1Data.value, chart1ColorList.value); let chart1 = getPieChart(chart1Data.value, chart1ColorList.value);
setChart(chart1, "chart1"); setChart(chart1, "chart1");
} catch (error) { } catch (error) {
if (isRequestCanceled(error)) {
return;
}
if (currentToken !== xzfsRequestToken.value) { if (currentToken !== xzfsRequestToken.value) {
return; return;
} }
...@@ -701,7 +734,7 @@ const handleGetBillHyly = async () => { ...@@ -701,7 +734,7 @@ const handleGetBillHyly = async () => {
}; };
try { try {
const res = await getBillHyly(params); const res = await getBillHyly(params, { signal: getPageSignal() });
if (currentToken !== hylyRequestToken.value) { if (currentToken !== hylyRequestToken.value) {
return; return;
} }
...@@ -729,6 +762,9 @@ const handleGetBillHyly = async () => { ...@@ -729,6 +762,9 @@ const handleGetBillHyly = async () => {
let chart2 = getPieChart(chart2Data.value, chart2ColorList.value); let chart2 = getPieChart(chart2Data.value, chart2ColorList.value);
setChart(chart2, "chart2"); setChart(chart2, "chart2");
} catch (error) { } catch (error) {
if (isRequestCanceled(error)) {
return;
}
if (currentToken !== hylyRequestToken.value) { if (currentToken !== hylyRequestToken.value) {
return; return;
} }
...@@ -745,6 +781,14 @@ onMounted(async () => { ...@@ -745,6 +781,14 @@ onMounted(async () => {
await handleGetBillContentXzfs(); await handleGetBillContentXzfs();
await handleGetBillHyly(); await handleGetBillHyly();
}); });
onBeforeRouteLeave(() => {
stopCurrentPageRequests();
});
onBeforeUnmount(() => {
stopCurrentPageRequests();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论