added cosmic, added passcode

This commit is contained in:
Dustella 2025-01-18 22:00:26 +08:00
parent f80f93a9b3
commit 52deafb19f
17 changed files with 275 additions and 51 deletions

2
auto-imports.d.ts vendored
View File

@ -9,6 +9,7 @@ declare global {
const EffectScope: typeof import('vue')['EffectScope']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const baseFetch: typeof import('./src/composables/fetch')['baseFetch']
const computed: typeof import('vue')['computed']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
const computedEager: typeof import('@vueuse/core')['computedEager']
@ -309,6 +310,7 @@ declare module 'vue' {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
readonly baseFetch: UnwrapRef<typeof import('./src/composables/fetch')['baseFetch']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly computedAsync: UnwrapRef<typeof import('@vueuse/core')['computedAsync']>
readonly computedEager: UnwrapRef<typeof import('@vueuse/core')['computedEager']>

View File

@ -107,11 +107,23 @@ const data = {
isActive: true,
items: [
{
title: '波动',
title: '行星波月统计',
url: '/tidi/waves',
},
],
},
{
title: 'COSMIC',
url: '#',
icon: 'mdi:telescope',
isActive: true,
items: [
{
title: '行星波月统计',
url: '/cosmic/stats',
},
],
},
],
关于: [

111
src/components/CoolBack.vue Normal file
View File

@ -0,0 +1,111 @@
<script setup lang="ts">
import type { P5I } from 'p5i'
import { p5i } from 'p5i'
import { onMounted, onUnmounted, ref } from 'vue'
const el = ref<HTMLCanvasElement | null>(null)
const {
mount,
unmount,
createCanvas,
background,
noFill,
stroke,
noise,
noiseSeed,
resizeCanvas,
cos,
sin,
TWO_PI,
} = p5i()
let w = window.innerWidth
let h = window.innerHeight
const offsetY = window.scrollY
const SCALE = 200
const LENGTH = 10
const SPACING = 15
function getForceOnPoint(x: number, y: number, z: number) {
// https://p5js.org/reference/#/p5/noise
return (noise(x / SCALE, y / SCALE, z) - 0.5) * 2 * TWO_PI
}
const existingPoints = new Set<string>()
const points: { x: number, y: number, opacity: number }[] = []
function addPoints() {
for (let x = -SPACING / 2; x < w + SPACING; x += SPACING) {
for (let y = -SPACING / 2; y < h + offsetY + SPACING; y += SPACING) {
const id = `${x}-${y}`
if (existingPoints.has(id))
continue
existingPoints.add(id)
points.push({ x, y, opacity: Math.random() * 0.5 + 0.5 })
}
}
}
function setup() {
createCanvas(w, h)
background('#ffffff')
stroke('#ccc')
noFill()
noiseSeed(+new Date())
addPoints()
}
function draw({ circle }: P5I) {
background('#ffffff')
const t = +new Date() / 10000
for (const p of points) {
const { x, y } = p
const rad = getForceOnPoint(x, y, t)
const length = (noise(x / SCALE, y / SCALE, t * 2) + 0.5) * LENGTH
const nx = x + cos(rad) * length
const ny = y + sin(rad) * length
stroke(180, 180, 180, (Math.abs(cos(rad)) * 0.5 + 0.5) * p.opacity * 255)
circle(nx, ny - offsetY, 1)
}
}
function restart() {
if (el.value)
mount(el.value, { setup, draw })
}
onMounted(() => {
restart()
useEventListener('resize', () => {
w = window.innerWidth
h = window.innerHeight
resizeCanvas(w, h)
addPoints()
})
// Uncomment to enable scroll-based animation
// Tho there is some lag when scrolling, not sure if it's solvable
// useEventListener('scroll', () => {
// offsetY = window.scrollY
// addPoints()
// }, { passive: true })
})
onUnmounted(() => {
unmount()
})
</script>
<template>
<!-- <Paper> -->
<div relative h-100 class="overflow-hidden">
<div ref="el" pointer-events-none overflow-hidden />
</div>
<!-- </Paper> -->
</template>

21
src/composables/fetch.ts Normal file
View File

@ -0,0 +1,21 @@
import { createFetch } from '@vueuse/core'
import { API_BASE_URL } from '~/CONSTANT'
export const baseFetch = createFetch({
baseUrl: API_BASE_URL,
options: {
async beforeFetch({ options }) {
const code = '0101'
options.headers = {
...options.headers,
Authorization: `${code}`,
}
return { options }
},
},
fetchOptions: {
mode: 'cors',
},
})

View File

@ -1 +1,2 @@
export * from './dark'
export * from './fetch'

View File

@ -35,11 +35,12 @@ const form = useForm()
const stagedDates = ref<string[]>([])
onMounted(async () => {
await fetch(`${API_BASE_URL}/balloon/metadata`).then(resp => resp.json()).then((data) => {
stagedDates.value = data
await baseFetch<string []>(`${API_BASE_URL}/balloon/metadata`).json().then(({ data }) => {
const das = data.value!
stagedDates.value = das
formSchema.value = z.object({
selectedMode: z.enum(modes).describe('选择一个模式'),
selectedDate: z.enum(data.map((d: string) => {
selectedDate: z.enum(das.map((d: string) => {
const datePattern = /_\d{8}T\d{6}/
if (!datePattern.test(d)) {
return ''
@ -51,7 +52,7 @@ onMounted(async () => {
return capture[0]
})),
}).describe('选择一个日期')
form.setFieldValue('selectedDate', data[0])
form.setFieldValue('selectedDate', data.value![0])
form.setFieldValue('selectedMode', modes[0])
})
})
@ -60,8 +61,9 @@ async function get_image(
selectedMode: string,
selectedDate: string,
) {
const resp = await fetch(`${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

View File

@ -44,8 +44,8 @@ const modes = [
async function refreshImage() {
const url = `${API_BASE_URL}/balloon/render/year?mode=${encodeURIComponent(selectedMode.value)}&start_year=${startYear.value}&end_year=${endYear.value}`
const resp = await fetch(url)
const blob = await resp.blob()
const { data } = await baseFetch(url).arrayBuffer()
const blob = new Blob([data.value!])
const u = URL.createObjectURL(blob)
imageResult.result = 'success'
imageResult.imageUrl = u

View File

@ -0,0 +1,64 @@
<route lang="json">
{"meta":{
"title":"COSMIC",
"description":"行星波月统计",
"group":"COSMIC",
"item_name":"行星波月统计"
}}
</route>
<script setup lang="ts">
import type { ImageResult } from '~/components/ImageContainer.vue'
import DenseFramework from '~/components/DenseFramework.vue'
import { API_BASE_URL } from '~/CONSTANT'
const imageResult = reactive<ImageResult>({
result: 'idle',
imageUrl: '',
message: '',
})
const selectedT = ref<'5' | '10' | '16'>('5')
const fetchUrl = computed(() => {
const query = new URLSearchParams()
query.set('T_', selectedT.value)
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>
<template>
<DenseFramework :image-result="imageResult" @submit="execute">
<Label for="T_range">滑动窗口</Label>
<Tabs id="T_range" v-model="selectedT" default-value="5">
<TabsList class="grid grid-cols-3 w-full">
<TabsTrigger value="5">
5
</TabsTrigger>
<TabsTrigger value="10">
10
</TabsTrigger>
<TabsTrigger value="16">
16
</TabsTrigger>
</TabsList>
</Tabs>
</DenseFramework>
</template>

View File

@ -13,7 +13,7 @@
import type { ImageResult } from '~/components/ImageContainer.vue'
import { API_BASE_URL } from '~/CONSTANT'
const selectedMode = ref('潮汐波')
const selectedMode = ref('2日行星波')
const selectedWave = ref('潮汐波')
const selectedDateType = ref('day')
const selectedStation = ref('武汉左岭镇站')
@ -68,7 +68,7 @@ const queryUrl = computed(() => {
return path
})
const { onFetchResponse, isFetching, execute } = useFetch(queryUrl, { immediate: false })
const { onFetchResponse, isFetching, execute } = baseFetch(queryUrl, { immediate: false })
onFetchResponse(async (resp) => {
const blob = await resp.blob()
@ -84,8 +84,8 @@ watch(isFetching, (fetching) => {
})
onMounted(async () => {
const resp = await fetch(`${API_BASE_URL}/radar/metadata`)
const data = await resp.json()
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\/(.*?)\//
@ -109,6 +109,12 @@ onMounted(async () => {
paths.value = data
})
watch(selectedYear, (newV) => {
selectedDate.value = Array.from(dates.value).filter(
d => d.startsWith(newV),
)[0]
})
</script>
<template>
@ -128,7 +134,7 @@ onMounted(async () => {
</Tabs>
<div v-if="selectedWave === '行星波'">
<Label>行星波类型</Label>
<Tabs v-model="selectedMode" default-value="uwind">
<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("行星波", "") }}

View File

@ -47,7 +47,7 @@ const queryUrl = computed(() => {
return path
})
const { onFetchResponse, isFetching, execute } = useFetch(queryUrl, { immediate: false })
const { onFetchResponse, isFetching, execute } = baseFetch(queryUrl, { immediate: false })
onFetchResponse(async (resp) => {
const blob = await resp.blob()
@ -63,8 +63,8 @@ watch(isFetching, (fetching) => {
})
onMounted(async () => {
const resp = await fetch(`${API_BASE_URL}/radar/metadata`)
const data = await resp.json()
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\/(.*?)\//

View File

@ -32,7 +32,7 @@ const urll = computed(() => {
const query = `path=${path}&day=${day}&cycle_no=${selected.cycle_no}`
return `${API_BASE_URL}/saber/render/day_cycle_power_wave_plot?${query}`
})
const { onFetchResponse, isFetching, execute } = useFetch(
const { onFetchResponse, isFetching, execute } = baseFetch(
urll,
{ immediate: false },
)
@ -50,20 +50,23 @@ onFetchResponse(async (resp) => {
imageResult.imageUrl = url
})
onMounted(() => {
refreshPath()
onMounted(async () => {
await refreshPath()
selected.path = saberPaths.value[0]
})
watch(() => selected.path, () => {
refreshCurrentSaberDays(selected.path)
if (selected.day === '') {
watch(() => selected.path, async () => {
if (selected.path === '') {
return
}
await refreshCurrentSaberDays(selected.path)
if (selected.day === '' && currentSaberDays.value.length > 0) {
selected.day = currentSaberDays.value[0]
}
})
function renderPath(path: string) {
const yearPattern = /\/data\\(\d{4})/
const yearPattern = /\/data\/(\d{4})/
const year = path.match(yearPattern)?.[1]
const monthPattern = /Temp_O3_(.*)(\d{4})/
const month = path.match(monthPattern)?.[1]

View File

@ -32,7 +32,7 @@ const urll = computed(() => {
const query = `path=${path}&day=${day}&cycle_no=${selected.cycle_no}`
return `${API_BASE_URL}/saber/render/day_fft_ifft_plot?${query}`
})
const { onFetchResponse, isFetching, execute } = useFetch(
const { onFetchResponse, isFetching, execute } = baseFetch(
urll,
{ immediate: false },
)
@ -50,20 +50,20 @@ onFetchResponse(async (resp) => {
imageResult.imageUrl = url
})
onMounted(() => {
refreshPath()
onMounted(async () => {
await refreshPath()
selected.path = saberPaths.value[0]
})
watch(() => selected.path, () => {
refreshCurrentSaberDays(selected.path)
watch(() => selected.path, async () => {
await refreshCurrentSaberDays(selected.path)
if (selected.day === '') {
selected.day = currentSaberDays.value[0]
}
})
function renderPath(path: string) {
const yearPattern = /\/data\\(\d{4})/
const yearPattern = /\/data\/(\d{4})/
const year = path.match(yearPattern)?.[1]
const monthPattern = /Temp_O3_(.*)(\d{4})/
const month = path.match(monthPattern)?.[1]

View File

@ -29,7 +29,7 @@ const urll = computed(() => {
const query = `path=${path}`
return `${API_BASE_URL}/saber/render/month_power_wave_plot?${query}`
})
const { onFetchResponse, execute, isFetching } = useFetch(
const { onFetchResponse, execute, isFetching } = baseFetch(
urll,
{ immediate: false },
)
@ -47,13 +47,13 @@ onFetchResponse(async (resp) => {
imageResult.imageUrl = url
})
onMounted(() => {
refreshPath()
onMounted(async () => {
await refreshPath()
selected.path = saberPaths.value[0]
})
function renderPath(path: string) {
const yearPattern = /\/data\\(\d{4})/
const yearPattern = /\/data\/(\d{4})/
const year = path.match(yearPattern)?.[1]
const monthPattern = /Temp_O3_(.*)(\d{4})/
const month = path.match(monthPattern)?.[1]

View File

@ -32,7 +32,7 @@ const urll = computed(() => {
const query = `path=${path}&day=${day}&height=${selected.height_no}`
return `${API_BASE_URL}/saber/render/plot_wave_fitting?${query}`
})
const { onFetchResponse, execute, isFetching } = useFetch(
const { onFetchResponse, execute, isFetching } = baseFetch(
urll,
{ immediate: false },
)
@ -50,20 +50,20 @@ onFetchResponse(async (resp) => {
imageResult.imageUrl = url
})
onMounted(() => {
refreshPath()
onMounted(async () => {
await refreshPath()
selected.path = saberPaths.value[0]
})
watch(() => selected.path, () => {
refreshCurrentSaberDays(selected.path)
watch(() => selected.path, async () => {
await refreshCurrentSaberDays(selected.path)
if (saberPaths.value.length > 0) {
selected.path = saberPaths.value[0]
}
})
function renderPath(path: string) {
const yearPattern = /\/data\\(\d{4})/
const yearPattern = /\/data\/(\d{4})/
const year = path.match(yearPattern)?.[1]
const monthPattern = /Temp_O3_(.*)(\d{4})/
const month = path.match(monthPattern)?.[1]

View File

@ -6,15 +6,15 @@ const currentSaberDays = ref<string>('')
async function refreshPath() {
if (saberPaths.value.length)
return
const resp = await fetch(`${API_BASE_URL}/saber/metadata`)
const data = await resp.json()
saberPaths.value = data
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 fetch(`${API_BASE_URL}/saber/metadata/list_days?path=${path}`)
const data = await resp.json()
currentSaberDays.value = data
const resp = await baseFetch<string>(`${API_BASE_URL}/saber/metadata/list_days?path=${path}`).json()
const data = resp.data.value
currentSaberDays.value = data!
}
export { currentSaberDays, refreshCurrentSaberDays, refreshPath, saberPaths }

View File

@ -15,7 +15,7 @@ const selectedYear = ref('2017')
// const k = [ -4,-3,-2,-1,0,1,2,3,4]
const selectedK = ref(0)
const selectedT = ref(15)
const selectedT = ref('5')
const queryUrl = computed(() => {
const query = new URLSearchParams()
@ -26,7 +26,7 @@ const queryUrl = computed(() => {
return `${API_BASE_URL}/tidi/render/wave?${query}`
})
const { execute, onFetchResponse, isFetching } = useFetch(queryUrl, { immediate: false })
const { execute, onFetchResponse, isFetching } = baseFetch(queryUrl, { immediate: false })
watch(isFetching, (fetching) => {
if (fetching) {
@ -42,13 +42,14 @@ onFetchResponse(async (resp) => {
})
onMounted(async () => {
const metas = await fetch(`${API_BASE_URL}/tidi/metadata`).then(resp => resp.json())
const _years = metas.path.map((a: string) => {
const metas = await baseFetch<{ path: string [] }>(`${API_BASE_URL}/tidi/metadata`).json()
const _years = metas.data.value.path.map((a: string) => {
const year_pattern = /data\/(\d{4})\//
return a.match(year_pattern)?.[1]
})
_years.sort()
years.value = Array.from(new Set(_years))
selectedYear.value = years.value[0]
})
</script>
@ -100,8 +101,8 @@ onMounted(async () => {
<TabsTrigger value="10">
10
</TabsTrigger>
<TabsTrigger value="15">
15
<TabsTrigger value="16">
16
</TabsTrigger>
</TabsList>
</Tabs>

1
typed-router.d.ts vendored
View File

@ -22,6 +22,7 @@ declare module 'vue-router/auto-routes' {
'/[...all]': RouteRecordInfo<'/[...all]', '/:all(.*)', { all: ParamValue<true> }, { all: ParamValue<false> }>,
'/balloon/single': RouteRecordInfo<'/balloon/single', '/balloon/single', Record<never, never>, Record<never, never>>,
'/balloon/year': RouteRecordInfo<'/balloon/year', '/balloon/year', Record<never, never>, Record<never, never>>,
'/cosmic/stats': RouteRecordInfo<'/cosmic/stats', '/cosmic/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>>,