219 lines
6.4 KiB
Vue
219 lines
6.4 KiB
Vue
<template>
|
||
<div class="min-h-screen bg-gray-50">
|
||
<van-nav-bar title="天远助手" left-arrow @click-left="goHome" fixed placeholder safe-area-inset-topxc z>
|
||
<template #right>
|
||
<van-button type="primary" size="small" class="!bg-blue-500 !border-blue-500" @click="goHome">
|
||
首页
|
||
</van-button>
|
||
</template>
|
||
</van-nav-bar>
|
||
|
||
<BaseReport v-if="queryState === 'success' && !isExpired" :isShare="true" :feature="feature"
|
||
:reportData="reportData" :reportParams="reportParams" :reportName="reportName"
|
||
:reportDateTime="reportDateTime" :isEmpty="isEmpty" :isDone="isDone" />
|
||
<div v-else-if="queryState === 'pending'" class="loading-container">
|
||
<div class="loading-spinner"></div>
|
||
<p>报告生成中,请稍候...</p>
|
||
</div>
|
||
<div v-else-if="isExpired" class="expired-container">
|
||
<div class="expired-content">
|
||
<van-icon name="clock-o" size="48" color="#999" />
|
||
<h2 class="text-xl font-bold text-gray-700 mt-4">
|
||
分享链接已过期
|
||
</h2>
|
||
<p class="text-gray-500 mt-2">
|
||
该分享链接已超过7天有效期,请重新获取分享链接
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="p-4" v-else-if="queryState === 'failed'">
|
||
<LEmpty />
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import LEmpty from "@/components/LEmpty.vue";
|
||
import { useRouter } from "vue-router";
|
||
|
||
const router = useRouter();
|
||
const route = useRoute();
|
||
const feature = ref("");
|
||
const reportData = ref([]);
|
||
const reportParams = ref({});
|
||
const reportName = ref("");
|
||
const reportDateTime = ref(null);
|
||
const isEmpty = ref(false);
|
||
const isDone = ref(false);
|
||
const isExpired = ref(false);
|
||
const queryState = ref("");
|
||
const pollingInterval = ref(null);
|
||
|
||
onBeforeMount(() => {
|
||
// 从动态路由参数中获取 linkIdentifier
|
||
const linkIdentifier = route.params.linkIdentifier;
|
||
if (!linkIdentifier) {
|
||
isEmpty.value = true;
|
||
isDone.value = true;
|
||
return;
|
||
}
|
||
|
||
// 解码 linkIdentifier
|
||
try {
|
||
const decodedLink = decodeURIComponent(linkIdentifier);
|
||
getReport(decodedLink);
|
||
} catch (err) {
|
||
console.error("分享链接无效");
|
||
isEmpty.value = true;
|
||
isDone.value = true;
|
||
}
|
||
});
|
||
|
||
onBeforeUnmount(() => {
|
||
if (pollingInterval.value) {
|
||
clearInterval(pollingInterval.value);
|
||
}
|
||
});
|
||
|
||
const getReport = async (linkId) => {
|
||
if (!linkId) return;
|
||
|
||
const { data, error } = await useApiFetch(`/query/share/${linkId}`)
|
||
.get()
|
||
.json();
|
||
|
||
if (data.value && !error.value) {
|
||
if (data.value.code === 200) {
|
||
// 检查分享链接状态
|
||
if (data.value.data.status === "expired") {
|
||
isExpired.value = true;
|
||
isDone.value = true;
|
||
// 如果过期,清除轮询
|
||
if (pollingInterval.value) {
|
||
clearInterval(pollingInterval.value);
|
||
pollingInterval.value = null;
|
||
}
|
||
return;
|
||
}
|
||
|
||
queryState.value = data.value.data.query_state;
|
||
if (queryState.value === "success") {
|
||
reportData.value = data.value.data.query_data.sort((a, b) => {
|
||
return a.feature.sort - b.feature.sort;
|
||
});
|
||
feature.value = data.value.data.product;
|
||
reportParams.value = data.value.data.query_params;
|
||
reportName.value = data.value.data.product_name;
|
||
reportDateTime.value = data.value.data.create_time;
|
||
isDone.value = true;
|
||
|
||
// 如果成功,清除轮询
|
||
if (pollingInterval.value) {
|
||
clearInterval(pollingInterval.value);
|
||
pollingInterval.value = null;
|
||
}
|
||
} else if (queryState.value === "pending") {
|
||
// 如果是pending状态且没有轮询,启动轮询
|
||
if (!pollingInterval.value) {
|
||
pollingInterval.value = setInterval(() => {
|
||
getReport(linkId);
|
||
}, 2000); // 每2秒轮询一次
|
||
}
|
||
} else if (queryState.value === "failed") {
|
||
isEmpty.value = true;
|
||
isDone.value = true;
|
||
// 如果失败,清除轮询
|
||
if (pollingInterval.value) {
|
||
clearInterval(pollingInterval.value);
|
||
pollingInterval.value = null;
|
||
}
|
||
}
|
||
} else if (data.value.code === 200003) {
|
||
isEmpty.value = true;
|
||
isDone.value = true;
|
||
} else if (data.value.code === 200002) {
|
||
isPending.value = true;
|
||
isDone.value = true;
|
||
}
|
||
}
|
||
};
|
||
|
||
const goHome = () => {
|
||
router.push("/");
|
||
};
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.loading-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 100vh;
|
||
|
||
.loading-spinner {
|
||
width: 50px;
|
||
height: 50px;
|
||
border: 4px solid #f3f3f3;
|
||
border-top: 4px solid #3498db;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
p {
|
||
color: #666;
|
||
font-size: 16px;
|
||
}
|
||
}
|
||
|
||
.expired-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
min-height: 100vh;
|
||
background-color: #f8f9fa;
|
||
padding: 20px;
|
||
|
||
.expired-content {
|
||
text-align: center;
|
||
padding: 40px;
|
||
background: white;
|
||
border-radius: 12px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
||
max-width: 400px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% {
|
||
transform: rotate(0deg);
|
||
}
|
||
100% {
|
||
transform: rotate(360deg);
|
||
}
|
||
}
|
||
|
||
:deep(.van-nav-bar) {
|
||
.van-nav-bar__title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.van-nav-bar__left {
|
||
.van-icon {
|
||
color: #333;
|
||
}
|
||
}
|
||
}
|
||
|
||
:deep(.van-button) {
|
||
height: 32px;
|
||
padding: 0 16px;
|
||
font-size: 14px;
|
||
}
|
||
</style>
|