refactor: new imageFetch

This commit is contained in:
Dustella 2025-01-23 22:06:53 +08:00
parent 247d7e37db
commit 69df9232e0
12 changed files with 97 additions and 249 deletions

View File

@ -6,11 +6,55 @@ import {
ResizablePanelGroup, ResizablePanelGroup,
} from '~/components/ui/resizable' } from '~/components/ui/resizable'
defineProps<{ const props = defineProps<{
imageResult: ImageResult imageQuery: string
extraErrorHandle?: (resp: Response) => {
type: string
message: string
}
extraResponseHandle?: (resp: Response) => Promise<ImageResult>
}>() }>()
defineEmits(['submit']) defineEmits(['submit'])
const imageResult = reactive<ImageResult>({
result: 'idle',
resourceId: '',
message: '请你选择一个模式和日期',
})
const urlRef = computed(() => {
return props.imageQuery
})
const { onFetchResponse, onFetchError, isFetching, execute } = baseFetch(
urlRef,
{ immediate: false },
)
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
if (props.extraResponseHandle) {
const newResult = await props.extraResponseHandle(resp)
imageResult.result = newResult.result
imageResult.resourceId = newResult.resourceId
imageResult.message = newResult.message
}
else {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.resourceId = url
}
})
onFetchError(async (error) => {
imageResult.result = 'error'
imageResult.message = error
})
</script> </script>
<template> <template>
@ -22,7 +66,10 @@ defineEmits(['submit'])
> >
<ResizablePanel id="demo-panel-1" :default-size="200" py-5> <ResizablePanel id="demo-panel-1" :default-size="200" py-5>
<ParamsCard <ParamsCard
@submit="$emit('submit')" @submit="() => {
$emit('submit')
execute()
}"
> >
<slot /> <slot />
</ParamsCard> </ParamsCard>

View File

@ -3,7 +3,7 @@ import { Icon } from '@iconify/vue/dist/iconify.js'
export interface ImageResult { export interface ImageResult {
result: 'success' | 'error' | 'pending' | 'idle' result: 'success' | 'error' | 'pending' | 'idle'
imageUrl: string resourceId: string
message?: string message?: string
} }
@ -14,7 +14,7 @@ const props = defineProps<{
function download() { function download() {
if (props.imageResult.result === 'success') { if (props.imageResult.result === 'success') {
const a = document.createElement('a') const a = document.createElement('a')
a.href = props.imageResult.imageUrl a.href = props.imageResult.resourceId
a.download = 'image.png' a.download = 'image.png'
a.click() a.click()
} }
@ -30,7 +30,7 @@ function download() {
<Icon icon="akar-icons:loading" class="mr-2 animate-spin" /> <Icon icon="akar-icons:loading" class="mr-2 animate-spin" />
<span>正在加载图片</span> <span>正在加载图片</span>
</div> </div>
<Image v-else-if="imageResult.result === 'success'" class="flex flex-1 items-center justify-center text-xl" :image-url="imageResult.imageUrl" /> <Image v-else-if="imageResult.result === 'success'" class="flex flex-1 items-center justify-center text-xl" :image-url="imageResult.resourceId" />
<div v-else class="flex flex-1 items-center justify-center text-xl"> <div v-else class="flex flex-1 items-center justify-center text-xl">
{{ imageResult.message }} {{ imageResult.message }}
</div> </div>

View File

@ -12,12 +12,6 @@ import { useForm } from 'vee-validate'
import { z } from 'zod' import { z } from 'zod'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const modes = [ const modes = [
'观测的二阶多项式拟合', '观测的二阶多项式拟合',
'扰动分量的正弦波拟合', '扰动分量的正弦波拟合',
@ -57,35 +51,42 @@ onMounted(async () => {
}) })
}) })
async function get_image( const queryUrl = computed(() => {
selectedMode: string, const selectedMode = form.values.selectedMode
selectedDate: string, const selectedDate = stagedDates.value.find(d => d.includes(form.values.selectedDate))!
) { return `${API_BASE_URL}/balloon/render/single?mode=${encodeURIComponent(selectedMode)}&path=${encodeURIComponent(selectedDate)}`
const { response } = await baseFetch(`${API_BASE_URL}/balloon/render/single?mode=${encodeURIComponent(selectedMode)}&path=${encodeURIComponent(selectedDate)}`) })
// check for MIME Type, check if is png
const resp = response.value!
const isPng = resp.headers.get('Content-Type') === 'image/png'
if (!isPng) {
imageResult.result = 'error' as const
imageResult.message = '这一天没有数据'
return
}
imageResult.result = 'success' as const
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.imageUrl = url
}
function submit() { async function customHandle(resp: Response) {
const value = form.values if (resp.status === 204) {
const selectedMode = value.selectedMode const res: ImageResult = {
const selectedDate = stagedDates.value.find(d => d.includes(value.selectedDate)) message: '这一天没有数据',
get_image(selectedMode, selectedDate!) result: 'error',
resourceId: '',
}
return res
}
if (resp.status === 200) {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
const res: ImageResult = {
message: '成功',
result: 'success',
resourceId: url,
}
return res
}
return {
message: '未知错误',
result: 'error',
resourceId: '',
} as ImageResult
} }
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="submit"> <DenseFramework :image-query="queryUrl" :extra-response-handle="customHandle">
<AutoForm <AutoForm
:form="form" :form="form"
:field-config="{ :field-config="{

View File

@ -7,17 +7,10 @@ meta:
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
const selectedMode = ref('w/f值统计结果') const selectedMode = ref('w/f值统计结果')
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const isIllegal = ref(false) const isIllegal = ref(false)
const startYear = ref(2017) const startYear = ref(2017)
@ -60,14 +53,9 @@ const mode_display_mapping = {
'动能和势能分布情况': '动能和势能分布情况', '动能和势能分布情况': '动能和势能分布情况',
} }
async function refreshImage() { const queryUrl = computed(() => {
const url = `${API_BASE_URL}/balloon/render/year?mode=${encodeURIComponent(selectedMode.value)}&start_year=${startYear.value}&end_year=${endYear.value}` return `${API_BASE_URL}/balloon/render/year?mode=${encodeURIComponent(selectedMode.value)}&start_year=${startYear.value}&end_year=${endYear.value}`
const { data } = await baseFetch(url).arrayBuffer() })
const blob = new Blob([data.value!])
const u = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = u
}
watch([selectedMode, startYear, endYear], () => { watch([selectedMode, startYear, endYear], () => {
if (startYear.value > endYear.value) { if (startYear.value > endYear.value) {
@ -79,7 +67,7 @@ watch([selectedMode, startYear, endYear], () => {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="refreshImage"> <DenseFramework :image-query="queryUrl">
<div flex="col gap-5 ~ justify-center"> <div flex="col gap-5 ~ justify-center">
<div> <div>
<Label>统计参数</Label> <Label>统计参数</Label>

View File

@ -8,16 +8,9 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import DenseFramework from '~/components/DenseFramework.vue' import DenseFramework from '~/components/DenseFramework.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '',
})
const selectedT = ref<'5' | '10' | '16'>('5') const selectedT = ref<'5' | '10' | '16'>('5')
const fetchUrl = computed(() => { const fetchUrl = computed(() => {
@ -25,27 +18,10 @@ const fetchUrl = computed(() => {
query.set('T_', selectedT.value) query.set('T_', selectedT.value)
return `${API_BASE_URL}/cosmic/temp_render?${query}` return `${API_BASE_URL}/cosmic/temp_render?${query}`
}) })
const { onFetchResponse, isFetching, execute } = baseFetch(fetchUrl, {
immediate: false,
})
watch(isFetching, (isFetching) => {
if (isFetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="fetchUrl">
<Label for="T_range">行星波周期</Label> <Label for="T_range">行星波周期</Label>
<Tabs id="T_range" v-model="selectedT" default-value="5"> <Tabs id="T_range" v-model="selectedT" default-value="5">
<TabsList class="grid grid-cols-3 w-full"> <TabsList class="grid grid-cols-3 w-full">

View File

@ -10,7 +10,6 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
const selectedMode = ref('2日行星波') const selectedMode = ref('2日行星波')
@ -23,12 +22,6 @@ const selectedH = ref(94000)
const selectedDate = ref('20170316') const selectedDate = ref('20170316')
const selectedMonth = ref('1') const selectedMonth = ref('1')
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const modes = [ const modes = [
'2日行星波', '2日行星波',
'5日行星波', '5日行星波',
@ -68,21 +61,6 @@ const queryUrl = computed(() => {
return path return path
}) })
const { onFetchResponse, isFetching, execute } = baseFetch(queryUrl, { immediate: false })
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onMounted(async () => { onMounted(async () => {
const resp = await baseFetch(`${API_BASE_URL}/radar/metadata`).json() const resp = await baseFetch(`${API_BASE_URL}/radar/metadata`).json()
const data = await resp.data.value const data = await resp.data.value
@ -118,7 +96,7 @@ watch(selectedYear, (newV) => {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="queryUrl">
<div> <div>
<div flex="~ col gap-3" py-3> <div flex="~ col gap-3" py-3>
<Label for="waves">波类型</Label> <Label for="waves">波类型</Label>

View File

@ -10,7 +10,6 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
const selectedMode = ref('2日行星波') const selectedMode = ref('2日行星波')
@ -18,11 +17,6 @@ const selectedWave = ref('潮汐波')
const selectedStation = ref('武汉左岭镇站') const selectedStation = ref('武汉左岭镇站')
const selectedYear = ref('2017') const selectedYear = ref('2017')
const selectedMonthRange = reactive({ start: '1', end: '12' }) const selectedMonthRange = reactive({ start: '1', end: '12' })
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const modes = [ const modes = [
'2日行星波', '2日行星波',
@ -47,21 +41,6 @@ const queryUrl = computed(() => {
return path return path
}) })
const { onFetchResponse, isFetching, execute } = baseFetch(queryUrl, { immediate: false })
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onMounted(async () => { onMounted(async () => {
const resp = await baseFetch(`${API_BASE_URL}/radar/metadata`).json() const resp = await baseFetch(`${API_BASE_URL}/radar/metadata`).json()
const data = await resp.data.value! const data = await resp.data.value!
@ -87,7 +66,7 @@ onMounted(async () => {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="queryUrl">
<div> <div>
<div flex="~ col items-stretch gap-3" py-3> <div flex="~ col items-stretch gap-3" py-3>
<Label>计算模式</Label> <Label>计算模式</Label>

View File

@ -10,7 +10,6 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
import { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths } from './utils' import { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths } from './utils'
@ -20,35 +19,12 @@ const selected = reactive({
cycle_no: 1, cycle_no: 1,
}) })
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const urll = computed(() => { const urll = computed(() => {
const path = encodeURIComponent(selected.path) const path = encodeURIComponent(selected.path)
const day = encodeURIComponent(selected.day) const day = encodeURIComponent(selected.day)
const query = `path=${path}&day=${day}&cycle_no=${selected.cycle_no}` const query = `path=${path}&day=${day}&cycle_no=${selected.cycle_no}`
return `${API_BASE_URL}/saber/render/day_cycle_power_wave_plot?${query}` return `${API_BASE_URL}/saber/render/day_cycle_power_wave_plot?${query}`
}) })
const { onFetchResponse, isFetching, execute } = baseFetch(
urll,
{ immediate: false },
)
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
onMounted(async () => { onMounted(async () => {
await refreshPath() await refreshPath()
@ -75,7 +51,7 @@ function renderPath(path: string) {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="urll">
<div> <div>
<div flex="~ col items-stretch gap-3" py-3> <div flex="~ col items-stretch gap-3" py-3>
<Label for="day">年月</Label> <Label for="day">年月</Label>

View File

@ -10,45 +10,21 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
import { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths } from './utils' import { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths } from './utils'
const selected = reactive({ const selected = reactive({
path: './saber/data\\2012\\SABER_Temp_O3_April2012_v2.0.nc', path: './saber/data/2012/SABER_Temp_O3_April2012_v2.0.nc',
day: '', day: '',
cycle_no: 1, cycle_no: 1,
}) })
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const urll = computed(() => { const urll = computed(() => {
const path = encodeURIComponent(selected.path) const path = encodeURIComponent(selected.path)
const day = encodeURIComponent(selected.day) const day = encodeURIComponent(selected.day)
const query = `path=${path}&day=${day}&cycle_no=${selected.cycle_no}` const query = `path=${path}&day=${day}&cycle_no=${selected.cycle_no}`
return `${API_BASE_URL}/saber/render/day_fft_ifft_plot?${query}` return `${API_BASE_URL}/saber/render/day_fft_ifft_plot?${query}`
}) })
const { onFetchResponse, isFetching, execute } = baseFetch(
urll,
{ immediate: false },
)
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
onMounted(async () => { onMounted(async () => {
await refreshPath() await refreshPath()
@ -57,9 +33,6 @@ onMounted(async () => {
watch(() => selected.path, async () => { watch(() => selected.path, async () => {
await refreshCurrentSaberDays(selected.path) await refreshCurrentSaberDays(selected.path)
if (selected.day === '') {
selected.day = currentSaberDays.value[0]
}
}) })
function renderPath(path: string) { function renderPath(path: string) {
@ -72,7 +45,7 @@ function renderPath(path: string) {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="urll">
<div> <div>
<div flex="~ col items-stretch gap-3" py-3> <div flex="~ col items-stretch gap-3" py-3>
<Label for="day">年月</Label> <Label for="day">年月</Label>

View File

@ -10,7 +10,6 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
import { refreshPath, saberPaths } from './utils' import { refreshPath, saberPaths } from './utils'
@ -18,34 +17,11 @@ const selected = reactive({
path: '', path: '',
}) })
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const urll = computed(() => { const urll = computed(() => {
const path = encodeURIComponent(selected.path) const path = encodeURIComponent(selected.path)
const query = `path=${path}` const query = `path=${path}`
return `${API_BASE_URL}/saber/render/month_power_wave_plot?${query}` return `${API_BASE_URL}/saber/render/month_power_wave_plot?${query}`
}) })
const { onFetchResponse, execute, isFetching } = baseFetch(
urll,
{ immediate: false },
)
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
onMounted(async () => { onMounted(async () => {
await refreshPath() await refreshPath()
@ -62,7 +38,7 @@ function renderPath(path: string) {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="urll">
<div> <div>
<div flex="~ row items-center gap-3" py-3> <div flex="~ row items-center gap-3" py-3>
<Label for="day">年月</Label> <Label for="day">年月</Label>

View File

@ -10,7 +10,6 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
import { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths } from './utils' import { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths } from './utils'
@ -20,35 +19,12 @@ const selected = reactive({
height_no: 1, height_no: 1,
}) })
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const urll = computed(() => { const urll = computed(() => {
const path = encodeURIComponent(selected.path) const path = encodeURIComponent(selected.path)
const day = encodeURIComponent(selected.day) const day = encodeURIComponent(selected.day)
const query = `path=${path}&day=${day}&height=${selected.height_no}` const query = `path=${path}&day=${day}&height=${selected.height_no}`
return `${API_BASE_URL}/saber/render/plot_wave_fitting?${query}` return `${API_BASE_URL}/saber/render/plot_wave_fitting?${query}`
}) })
const { onFetchResponse, execute, isFetching } = baseFetch(
urll,
{ immediate: false },
)
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
onMounted(async () => { onMounted(async () => {
await refreshPath() await refreshPath()
@ -72,7 +48,7 @@ function renderPath(path: string) {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="urll">
<div> <div>
<div flex="~ col justify-stretch gap-3" py-3> <div flex="~ col justify-stretch gap-3" py-3>
<Label for="day">年月</Label> <Label for="day">年月</Label>

View File

@ -11,15 +11,8 @@
</route> </route>
<script setup lang="ts"> <script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT' import { API_BASE_URL } from '~/CONSTANT'
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '请你选择一个模式和日期',
})
const selectedMode = ref('V_Meridional') const selectedMode = ref('V_Meridional')
const years = ref([] as string[]) const years = ref([] as string[])
@ -38,21 +31,6 @@ const queryUrl = computed(() => {
return `${API_BASE_URL}/tidi/render/wave?${query}` return `${API_BASE_URL}/tidi/render/wave?${query}`
}) })
const { execute, onFetchResponse, isFetching } = baseFetch(queryUrl, { immediate: false })
watch(isFetching, (fetching) => {
if (fetching) {
imageResult.result = 'pending'
}
})
onFetchResponse(async (resp) => {
const blob = await resp.blob()
const url = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = url
})
onMounted(async () => { onMounted(async () => {
const metas = await baseFetch<{ path: string [] }>(`${API_BASE_URL}/tidi/metadata`).json() const metas = await baseFetch<{ path: string [] }>(`${API_BASE_URL}/tidi/metadata`).json()
const _years = metas.data.value.path.map((a: string) => { const _years = metas.data.value.path.map((a: string) => {
@ -66,7 +44,7 @@ onMounted(async () => {
</script> </script>
<template> <template>
<DenseFramework :image-result="imageResult" @submit="execute"> <DenseFramework :image-query="queryUrl">
<div flex="col gap-3 ~ justify-stretch"> <div flex="col gap-3 ~ justify-stretch">
<Label>计算模式</Label> <Label>计算模式</Label>
<Tabs id="modes" v-model="selectedMode" default-value="V_Meridional"> <Tabs id="modes" v-model="selectedMode" default-value="V_Meridional">