sync
Some checks failed
Test / build (lts/*, ubuntu-latest) (push) Has been cancelled
Test / build (lts/*, windows-latest) (push) Has been cancelled

This commit is contained in:
Dustella 2025-02-07 13:32:46 +08:00
parent 023258c9b9
commit 6d7d6cde37
17 changed files with 429 additions and 24 deletions

5
components.d.ts vendored
View File

@ -54,6 +54,8 @@ declare module 'vue' {
Collapsible: typeof import('./src/components/ui/collapsible/Collapsible.vue')['default']
CollapsibleContent: typeof import('./src/components/ui/collapsible/CollapsibleContent.vue')['default']
CollapsibleTrigger: typeof import('./src/components/ui/collapsible/CollapsibleTrigger.vue')['default']
Day_cycle_power_wave_plot: typeof import('./src/components/dense/saber/day_cycle_power_wave_plot.vue')['default']
Day_fft_ifft_plot: typeof import('./src/components/dense/saber/day_fft_ifft_plot.vue')['default']
DenseFramework: typeof import('./src/components/DenseFramework.vue')['default']
Drawer: typeof import('./src/components/ui/drawer/Drawer.vue')['default']
DrawerContent: typeof import('./src/components/ui/drawer/DrawerContent.vue')['default']
@ -101,6 +103,7 @@ declare module 'vue' {
MenubarSubContent: typeof import('./src/components/ui/menubar/MenubarSubContent.vue')['default']
MenubarSubTrigger: typeof import('./src/components/ui/menubar/MenubarSubTrigger.vue')['default']
MenubarTrigger: typeof import('./src/components/ui/menubar/MenubarTrigger.vue')['default']
Month_power_wave_plot: typeof import('./src/components/dense/saber/month_power_wave_plot.vue')['default']
NavigationMenu: typeof import('./src/components/ui/navigation-menu/NavigationMenu.vue')['default']
NavigationMenuContent: typeof import('./src/components/ui/navigation-menu/NavigationMenuContent.vue')['default']
NavigationMenuIndicator: typeof import('./src/components/ui/navigation-menu/NavigationMenuIndicator.vue')['default']
@ -116,9 +119,11 @@ declare module 'vue' {
NumberFieldIncrement: typeof import('./src/components/ui/number-field/NumberFieldIncrement.vue')['default']
NumberFieldInput: typeof import('./src/components/ui/number-field/NumberFieldInput.vue')['default']
ParamsCard: typeof import('./src/components/ParamsCard.vue')['default']
Plot_wave_fitting: typeof import('./src/components/dense/saber/plot_wave_fitting.vue')['default']
Popover: typeof import('./src/components/ui/popover/Popover.vue')['default']
PopoverContent: typeof import('./src/components/ui/popover/PopoverContent.vue')['default']
PopoverTrigger: typeof import('./src/components/ui/popover/PopoverTrigger.vue')['default']
RadarSingle: typeof import('./src/components/dense/RadarSingle.vue')['default']
RadioGroup: typeof import('./src/components/ui/radio-group/RadioGroup.vue')['default']
RadioGroupItem: typeof import('./src/components/ui/radio-group/RadioGroupItem.vue')['default']
ResizableHandle: typeof import('./src/components/ui/resizable/ResizableHandle.vue')['default']

View File

@ -65,12 +65,20 @@ const data = {
isActive: true,
items: [
{
title: '潮汐波强度',
url: '/radar/v1',
title: '潮汐波提取',
url: '/radar/TW-single',
},
{
title: '潮汐波时空变化',
url: '/radar/v2',
title: '潮汐波统计',
url: '/radar/TW-stats',
},
{
title: '行星波提取',
url: '/radar/PW-single',
},
{
title: '行星波统计',
url: '/radar/PW-stats',
},
],
},
@ -81,20 +89,12 @@ const data = {
isActive: true,
items: [
{
title: '波动拟合图',
url: '/saber/plot_wave_fitting',
title: '重力波提取',
url: '/saber/gw/single',
},
{
title: '日数据傅里叶变换分析',
url: '/saber/day_fft_ifft_plot',
},
{
title: '日周期波动能量分析',
url: '/saber/day_cycle_power_wave_plot',
},
{
title: '月度波动能量分析',
url: '/saber/month_power_wave_plot',
title: '重力波统计',
url: '/saber/gw/stats',
},
],

View File

@ -1,3 +1,4 @@
const KURONEKO_API = 'http://100.89.232.74:18200'
// export const API_BASE_URL = 'http://localhost:5000'
export const API_BASE_URL = import.meta.env.PROD ? 'https://gca-api.dustella.net:8443' : 'http://localhost:18200'
export const API_BASE_URL = import.meta.env.PROD ? 'https://gca-api.dustella.net:8443' : KURONEKO_API
// export const API_BASE_URL = 'https://gca-api.dustella.net:8443'

View File

@ -0,0 +1,226 @@
<script setup lang="ts">
import { API_BASE_URL } from '~/CONSTANT'
const props = defineProps<{
waveType: '潮汐波' | '行星波'
isDay?: boolean
}>()
const selectedWave = computed(() => props.waveType)
const selectedMode = ref('2日行星波')
const selectedDateType = ref('month')
const selectedStation = ref('武汉左岭镇站')
const selectedYear = ref('2017')
const selectedWindType = ref('uwind')
const selectedH = ref(94000)
const selectedDate = ref('20170316')
const selectedMonth = ref('1')
const modes = [
'2日行星波',
'5日行星波',
'10日行星波',
'16日行星波',
]
const paths = ref([] as string[])
const stations = ref<Set<string>>(new Set())
const years = ref<Set<string>>(new Set())
const dates = ref<Set<string>>(new Set())
const queryUrl = computed(() => {
const station = selectedStation.value
const year = encodeURIComponent(selectedYear.value)
const mode = selectedWave.value === '潮汐波'
? '潮汐波'
: selectedMode.value
const windType = selectedWindType.value
const query = new URLSearchParams()
query.set('station', station)
query.set('year', year)
query.set('model_name', mode)
query.set('wind_type', windType)
query.set('H', selectedH.value.toString())
query.set('mode', selectedDateType.value)
if (props.isDay) {
const queryDay = `${selectedDate.value.slice(0, 4)}-${selectedDate.value.slice(4, 6)}-${selectedDate.value.slice(6, 8)}`
query.set('day', queryDay)
}
else if (selectedDateType.value === 'month') {
query.set('month', selectedMonth.value)
}
// const query = `?station=${station}&year=${year}&model_name=${mode}&wind_type=${windType}&H=${selectedH.value}`
const path = `${API_BASE_URL}/radar/render/heatmap?${query}`
return path
})
const urlModel = defineModel<string>()
syncRef(urlModel, queryUrl, { direction: 'rtl' })
onMounted(async () => {
const resp = await baseFetch(`${API_BASE_URL}/radar/metadata`).json()
const data = await resp.data.value
// use regex to extract the year from the path,
// ./radar/data\\\\2017\\ZLT_MET01_DLL_L21_01D_20170316.txt
const station_pattern = /data\/(.*?)\//
const year_pattern = /(\d{4})\/ZLT_/
const date_pattern = /01D_(\d{8})\.txt/
const pairs = data.map((source_text: string) => {
const station = source_text.match(station_pattern)?.[1]
const year = source_text.match(year_pattern)?.[1]
const date = source_text.match(date_pattern)?.[1]
return { station, year, date }
})
pairs.forEach(({ station, year, date }: {
station: string
year: string
date: string
}) => {
stations.value.add(station)
years.value.add(year)
dates.value.add(date)
})
paths.value = data
})
watch(selectedYear, (newV) => {
selectedDate.value = Array.from(dates.value).filter(
d => d.startsWith(newV),
)[0]
})
</script>
<template>
<DenseFramework :image-query="queryUrl">
<div>
<div flex="~ col gap-3" py-3>
<div v-if="selectedWave === '行星波'">
<Label>行星波类型</Label>
<Tabs v-model="selectedMode" default-value="2日行星波">
<TabsList class="grid grid-cols-4 w-full">
<TabsTrigger v-for="m in modes" :key="m" :value="m">
{{ m.replace("行星波", "") }}
</TabsTrigger>
</TabsList>
</Tabs>
</div>
<Label for="wind_type">风类型</Label>
<Tabs id="wind_type" v-model="selectedWindType" default-value="uwind">
<TabsList class="grid grid-cols-2 w-full">
<TabsTrigger value="uwind">
纬向风
</TabsTrigger>
<TabsTrigger value="vwind">
经向风
</TabsTrigger>
</TabsList>
</Tabs>
<div v-if="!props.isDay">
<Label for="H">日期类型</Label>
<Tabs id="date_type" v-model="selectedDateType" default-value="month">
<TabsList class="grid grid-cols-3 w-full">
<!-- <TabsTrigger value="day">
</TabsTrigger> -->
<TabsTrigger value="month">
</TabsTrigger>
<TabsTrigger value="year">
</TabsTrigger>
</TabsList>
</Tabs>
</div>
<Label>观测站</Label>
<Select v-model="selectedStation">
<SelectTrigger>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>观测站</SelectLabel>
<SelectItem v-for="station in stations" :key="station" :value="station">
{{ station }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<Label>高度</Label>
<NumberField
id="start"
v-model:model-value="selectedH" :format-options="{
useGrouping: false,
}" :default-value="94000"
>
<NumberFieldContent>
<NumberFieldDecrement />
<NumberFieldInput />
<NumberFieldIncrement />
</NumberFieldContent>
</NumberField>
<Label>年份</Label>
<Select v-model="selectedYear">
<SelectTrigger>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel></SelectLabel>
<SelectItem v-for="year in years" :key="year" :value="year">
{{ year }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<div v-if="selectedDateType === 'day'">
<Label>日期</Label>
<Select v-model="selectedDate">
<SelectTrigger>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel></SelectLabel>
<SelectItem
v-for="date in Array.from(dates).filter(
(d) => d.startsWith(selectedYear),
)" :key="date" :value="date"
>
{{ date }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
<div v-if="selectedDateType === 'month'">
<Label>月份</Label>
<Select v-model="selectedMonth">
<SelectTrigger>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel></SelectLabel>
<SelectItem
v-for="month in [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
]" :key="month" :value="month.toString()"
>
{{ month }}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
</div>
</Denseframework>
</template>
<style lang="scss" scoped>
</style>

View File

@ -58,6 +58,7 @@ watch(() => selected.path, async () => {
<DenseFramework :image-query="urll">
<div>
<div flex="~ col items-stretch gap-3" py-3>
<slot />
<Label>纬度带</Label>
<Select v-model="selected.lat_range">
<SelectTrigger>

View File

@ -58,6 +58,7 @@ watch(() => selected.path, async () => {
<DenseFramework :image-query="urll">
<div>
<div flex="~ col items-stretch gap-3" py-3>
<slot />
<Label>纬度带</Label>
<Select v-model:model-value="selected.lat_range">
<SelectTrigger>

View File

@ -72,6 +72,7 @@ function mapHeightValue(input: number) {
<DenseFramework :image-query="urll">
<div>
<div flex="~ col justify-stretch gap-3" py-3>
<slot />
<Label>纬度带</Label>
<Select v-model="selected.lat_ranges">
<SelectTrigger>

View File

@ -0,0 +1,49 @@
import { API_BASE_URL } from '~/CONSTANT'
const saberPaths = ref<string[]>([])
const currentSaberDays = ref<string>('')
async function refreshPath() {
if (saberPaths.value.length)
return
const resp = await baseFetch<string[]>(`${API_BASE_URL}/saber/metadata`).json()
const data = resp.data.value
saberPaths.value = data!
}
async function refreshCurrentSaberDays(path: string) {
const resp = await baseFetch<string>(`${API_BASE_URL}/saber/metadata/list_days?path=${path}`).json()
const data = resp.data.value
currentSaberDays.value = data!
}
function renderPath(path: string) {
const yearPattern = /\/data\/(\d{4})/
const year = path.match(yearPattern)?.[1]
const monthPattern = /Temp_O3_(.*)(\d{4})/
const month_mapping = {
January: '01月',
February: '02月',
March: '03月',
April: '04月',
May: '05月',
June: '06月',
July: '07月',
August: '08月',
September: '09月',
October: '10月',
November: '11月',
December: '12月',
} as const
const month = path.match(monthPattern)?.[1] as keyof typeof month_mapping
return `${year}${month_mapping[month]}`
}
function parseDayOfYear(dateString: string): Date {
const year = Number.parseInt(dateString.substring(0, 4))
const dayOfYear = Number.parseInt(dateString.substring(4)) - 1 // subtract 1 because JS dates are 0-based
const date = new Date(year, 0) // Start with January 1st of the year
date.setDate(dayOfYear + 1) // Add the days
return date
}
export { currentSaberDays, parseDayOfYear, refreshCurrentSaberDays, refreshPath, renderPath, saberPaths }

View File

@ -0,0 +1,24 @@
<route lang="json">
{
"meta":{
"title":"流星雷达 行星波单次",
"description":"行星波提取",
"group":"流星雷达",
"item_name":"行星波提取"
}
}
</route>
<script setup lang="ts">
const url = ref('')
const mode = '行星波' as const
</script>
<template>
<RadarSingle is-day :model-value="url" :wave-type="mode" />
</template>
<style scoped>
</style>

View File

@ -0,0 +1,14 @@
<route lang="json">
{
"meta": {
"title": "流星雷达",
"description": "行星波统计",
"group": "流星雷达",
"item_name": "行星波统计"
}
}
</route>
<template>
<RadarSingle wave-type="行星波" />
</template>

View File

@ -0,0 +1,24 @@
<route lang="json">
{
"meta":{
"title":"潮汐波单次",
"description":"潮汐波提取",
"group":"流星雷达",
"item_name":"潮汐波提取"
}
}
</route>
<script setup lang="ts">
const url = ref('')
const mode = '潮汐波' as const
</script>
<template>
<RadarSingle :model-value="url" :wave-type="mode" :is-day="true" />
</template>
<style scoped>
</style>

View File

@ -0,0 +1,14 @@
<route lang="json">
{
"meta": {
"title": "流星雷达",
"description": "潮汐波统计",
"group": "流星雷达",
"item_name": "潮汐波统计"
}
}
</route>
<template>
<RadarSingle wave-type="潮汐波" />
</template>

View File

@ -0,0 +1,40 @@
<script setup lang="ts">
import Day_cycle_power_wave_plot from '~/components/dense/saber/day_cycle_power_wave_plot.vue'
import Day_fft_ifft_plot from '~/components/dense/saber/day_fft_ifft_plot.vue'
import Plot_wave_fitting from '~/components/dense/saber/plot_wave_fitting.vue'
const component_mapping = {
day_cycle_power_wave_plot: Day_cycle_power_wave_plot,
day_fft_ifft_plot: Day_fft_ifft_plot,
plot_wave_fitting: Plot_wave_fitting,
} as const
const currentMode = ref<keyof typeof component_mapping>('day_cycle_power_wave_plot')
const currentComponent = computed(() => {
return component_mapping[currentMode.value]
})
</script>
<template>
<component :is="currentComponent">
<div>
<Label>选择模式</Label>
<Tabs v-model="currentMode" class="w-full" default-value="day_cycle_power_wave_plot">
<TabsList class="grid grid-cols-1 w-full">
<TabsTrigger v-for="key in Object.keys(component_mapping)" :key="key" class="w-full" :value="key">
{{ {
day_cycle_power_wave_plot: '逐日波功率谱',
day_fft_ifft_plot: '逐日FFT/IFFT',
plot_wave_fitting: '逐日波形拟合',
}[key] }}
</TabsTrigger>
</TabsList>
</Tabs>
</div>
</component>
</template>
<style scoped>
</style>

View File

@ -0,0 +1,3 @@
<template>
<Month_power_wave_plot />
</template>

View File

@ -1,4 +1,4 @@
import { API_BASE_URL } from '~/CONSTANT'
import { ref } from 'vue'
const saberPaths = ref<string[]>([])
const currentSaberDays = ref<string>('')
@ -6,13 +6,13 @@ const currentSaberDays = ref<string>('')
async function refreshPath() {
if (saberPaths.value.length)
return
const resp = await baseFetch<string[]>(`${API_BASE_URL}/saber/metadata`).json()
const resp = await baseFetch<string[]>(`/saber/metadata`).json()
const data = resp.data.value
saberPaths.value = data!
}
async function refreshCurrentSaberDays(path: string) {
const resp = await baseFetch<string>(`${API_BASE_URL}/saber/metadata/list_days?path=${path}`).json()
const resp = await baseFetch<string>(`/saber/metadata/list_days?path=${path}`).json()
const data = resp.data.value
currentSaberDays.value = data!
}

10
typed-router.d.ts vendored
View File

@ -25,12 +25,14 @@ declare module 'vue-router/auto-routes' {
'/balloon/year': RouteRecordInfo<'/balloon/year', '/balloon/year', Record<never, never>, Record<never, never>>,
'/cosmic/single': RouteRecordInfo<'/cosmic/single', '/cosmic/single', Record<never, never>, Record<never, never>>,
'/cosmic/stats': RouteRecordInfo<'/cosmic/stats', '/cosmic/stats', Record<never, never>, Record<never, never>>,
'/radar/PW-single': RouteRecordInfo<'/radar/PW-single', '/radar/PW-single', Record<never, never>, Record<never, never>>,
'/radar/PW-stats': RouteRecordInfo<'/radar/PW-stats', '/radar/PW-stats', Record<never, never>, Record<never, never>>,
'/radar/TW-single': RouteRecordInfo<'/radar/TW-single', '/radar/TW-single', Record<never, never>, Record<never, never>>,
'/radar/TW-stats': RouteRecordInfo<'/radar/TW-stats', '/radar/TW-stats', Record<never, never>, Record<never, never>>,
'/radar/v1': RouteRecordInfo<'/radar/v1', '/radar/v1', Record<never, never>, Record<never, never>>,
'/radar/v2': RouteRecordInfo<'/radar/v2', '/radar/v2', Record<never, never>, Record<never, never>>,
'/saber/day_cycle_power_wave_plot': RouteRecordInfo<'/saber/day_cycle_power_wave_plot', '/saber/day_cycle_power_wave_plot', Record<never, never>, Record<never, never>>,
'/saber/day_fft_ifft_plot': RouteRecordInfo<'/saber/day_fft_ifft_plot', '/saber/day_fft_ifft_plot', Record<never, never>, Record<never, never>>,
'/saber/month_power_wave_plot': RouteRecordInfo<'/saber/month_power_wave_plot', '/saber/month_power_wave_plot', Record<never, never>, Record<never, never>>,
'/saber/plot_wave_fitting': RouteRecordInfo<'/saber/plot_wave_fitting', '/saber/plot_wave_fitting', Record<never, never>, Record<never, never>>,
'/saber/gw/single': RouteRecordInfo<'/saber/gw/single', '/saber/gw/single', Record<never, never>, Record<never, never>>,
'/saber/gw/stats': RouteRecordInfo<'/saber/gw/stats', '/saber/gw/stats', Record<never, never>, Record<never, never>>,
'/tidi/month_stats': RouteRecordInfo<'/tidi/month_stats', '/tidi/month_stats', Record<never, never>, Record<never, never>>,
'/tidi/waves': RouteRecordInfo<'/tidi/waves', '/tidi/waves', Record<never, never>, Record<never, never>>,
}