1 Commits

Author SHA1 Message Date
f5d3e7ea88 更新了搜索功能 (终于!) 1.1.0 版本 Release!
All checks were successful
Build / build-and-test (push) Successful in 33s
2025-05-26 11:23:24 +08:00
10 changed files with 160 additions and 47 deletions

View File

@ -16,5 +16,6 @@ export function createApp() {
.component('Hr', Hr) .component('Hr', Hr)
.component('BetterHr', Hr) .component('BetterHr', Hr)
.component('Form', Form) .component('Form', Form)
.component('BetterForm', Form)
return { app, pinia } return { app, pinia }
} }

View File

@ -39,21 +39,29 @@ export function createSSRRouter() {
title: '阅读', title: '阅读',
hidden: true hidden: true
} }
},{
path: '/search/simple',
name: '搜索',
component: () => import('./views/SimpleSearch.vue'),
meta: {
title: '搜索',
order: 2
}
},{ },{
path: '/settings', path: '/settings',
name: '设置', name: '设置',
component: () => import('./views/Settings.vue'), component: () => import('./views/Settings.vue'),
meta: { meta: {
title: '设置', title: '设置',
order: 2 order: 90
}, },
},{ },{
path: '/about', path: '/about',
name: '关于', name: '关于',
component: () => import('./views/About.vue'), component: () => import('./views/About.md'),
meta: { meta: {
title: '', title: '',
order: 3 order: 100
}, },
},{ },{
path: '/developer', path: '/developer',

51
src/stores/search.js Normal file
View File

@ -0,0 +1,51 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
import { useApiStore } from '@/stores/api.js'
export const useSimpleSearchState = defineStore('simpleSearch', () => {
const api = useApiStore()
const keyword = ref('')
const result = ref([])
const count = ref([])
const pageCount = ref(0)
const currentPage = ref(0)
const state = ref(null)
async function load() {
if (currentPage.value == pageCount.value) state.value = 'finish'
let res = await api.workSimpleSearch(keyword.value, currentPage.value)
res = res.data
if (res.code == 0) {
currentPage.value = res.page
pageCount.value = res.pageCount
count.value = res.count
state.value = import.meta.env.SSR ? 'ssrready' : 'ready'
result.value.push(...res.works)
} else if (res.code == 1) {
if (currentPage.value) {
state.value = 'finish'
} else {
currentPage.value = 1
state.value = 'notfound'
}
}
}
async function start(key) {
if (key == keyword.value) return
keyword.value = key
result.value = []
state.value = 'loading'
currentPage.value = 0
await load()
}
return {
keyword,
result,
count,
pageCount,
currentPage,
state,
load, start
}
})

View File

@ -10,7 +10,7 @@ export const useWorkReadState = defineStore('workRead', () => {
const id = ref(null) const id = ref(null)
const cid = ref(null) const cid = ref(null)
const summary = ref(null) const summary = ref(null)
const pesud = ref(null) const pseud = ref(null)
const title = ref(null) const title = ref(null)
const text = ref(null) const text = ref(null)
const state = ref('') const state = ref('')
@ -25,7 +25,7 @@ export const useWorkReadState = defineStore('workRead', () => {
id.value = data.workId id.value = data.workId
title.value = data.title title.value = data.title
summary.value = [escapeAndFormatText(data.summary)] summary.value = [escapeAndFormatText(data.summary)]
pesud.value = data.pesud pseud.value = data.pseud
text.value = data.text text.value = data.text
publishedTime.value = data.stats.publishedTime publishedTime.value = data.stats.publishedTime
wordCount.value = data.stats.wordCount wordCount.value = data.stats.wordCount
@ -51,7 +51,7 @@ export const useWorkReadState = defineStore('workRead', () => {
id, cid, id, cid,
title, title,
summary, summary,
pesud, pseud,
text, text,
state, state,
publishedTime, publishedTime,

View File

@ -1,9 +1,3 @@
# 欢迎来到 AO3 Mirror! 👋👋
一个基于重构渲染的 AO3 镜像站
---
## 这是什么🤨 ## 这是什么🤨
本网站是对 ArchiveOfOurOwn (AO3) 的一个镜像网站 本网站是对 ArchiveOfOurOwn (AO3) 的一个镜像网站
@ -45,3 +39,4 @@
- ✅ 作品详细数据 - ✅ 作品详细数据
- 📝 搜索 - 📝 搜索
- ❌ 书签 (本地) **不再支持! [详情](/about#deprecated-feature-bookmark)** - ❌ 书签 (本地) **不再支持! [详情](/about#deprecated-feature-bookmark)**

View File

@ -1,3 +1,18 @@
<script setup>
import About from '../texts/about.md'
import FunAnimation from '../components/FunAnimation.vue'
import 'mdui/components/avatar.js'
/*import { onBeforeMount, onMounted, onUnmounted, onBeforeUnmount, onActivated, onDeactivated } from 'vue'
console.log('Setup')
onBeforeMount(() => console.log('Before mount'))
onMounted(() => console.log('Mounted'))
onDeactivated(() => console.log('Deactivated'))
onActivated(() => console.log('Activated'))
onBeforeUnmount(() => console.log('Before unmount'))
onUnmounted(() => console.log('Unmounted'))*/
</script>
# 关于 # 关于
这是什么, 有口舍用 ? 这是什么, 有口舍用 ?
@ -43,3 +58,5 @@
本站支持 "Server Side Rendering" by Vite SSR 本站支持 "Server Side Rendering" by Vite SSR
CDN by Cloudflare (赛博佛祖😭) CDN by Cloudflare (赛博佛祖😭)
<FunAnimation />

View File

@ -1,19 +0,0 @@
<script setup>
import About from '../texts/about.md'
import FunAnimation from '../components/FunAnimation.vue'
import 'mdui/components/avatar.js'
/*import { onBeforeMount, onMounted, onUnmounted, onBeforeUnmount, onActivated, onDeactivated } from 'vue'
console.log('Setup')
onBeforeMount(() => console.log('Before mount'))
onMounted(() => console.log('Mounted'))
onDeactivated(() => console.log('Deactivated'))
onActivated(() => console.log('Activated'))
onBeforeUnmount(() => console.log('Before unmount'))
onUnmounted(() => console.log('Unmounted'))*/
</script>
<template>
<About/>
<FunAnimation />
</template>

View File

@ -9,9 +9,6 @@ import Intro from '../texts/intro.md'
const router = useRouter() const router = useRouter()
const err = ref(false)
const srcText = ref(null)
function convert(from) { function convert(from) {
if( Number(from) ) { if( Number(from) ) {
return { return {
@ -20,7 +17,6 @@ function convert(from) {
} }
} else if (from.includes('https://archiveofourown.org/works/')) { } else if (from.includes('https://archiveofourown.org/works/')) {
const sid = from.split('https://archiveofourown.org/works/')[1]; const sid = from.split('https://archiveofourown.org/works/')[1];
console.log(sid)
if ( sid ) { if ( sid ) {
const id = Number(sid) const id = Number(sid)
if (id) { if (id) {
@ -41,16 +37,15 @@ function convert(from) {
} }
} }
} }
return { type: null } return { type: 'f', key: from }
} }
function onConvert(data) { function onConvert(data) {
const { type, id, cid } = convert(data.src) const { type, id, cid, key } = convert(data.src)
if (type == null) { if (type == null) {
err.value = true } else if ( type == 'f') {
srcText.value?.focus() router.push(`/search/simple?keyword=${encodeURIComponent(key)}`)
} else { } else {
err.value = false
if (cid) router.push(`/work/${id}/${cid}`) if (cid) router.push(`/work/${id}/${cid}`)
else router.push(`/work/${id}`) else router.push(`/work/${id}`)
} }
@ -60,14 +55,14 @@ function onConvert(data) {
<template> <template>
<img style="display: block; margin: 0px auto 10px;" height="200px" alt="logo" src="/favicon.svg" /> <img style="display: block; margin: 0px auto 10px;" height="200px" alt="logo" src="/favicon.svg" />
<Intro /> <h1>欢迎来到 AO3 Mirror! 👋👋</h1>
<br/><Hr/> <p>一个基于重构渲染的 AO3 镜像站</p>
<Hr />
<section id="converter"> <section id="converter">
<h2>链接转换</h2> <h2>链接转换</h2>
<p>输入完整链接或者 ID</p> <p>AO3 链接 关键词搜索</p>
<Form @submit="onConvert"><ClientOnly> <Form @submit="onConvert"><ClientOnly>
<mdui-text-field variant="filled" label="链接" name="src" placeholder="https://archiveofourown.org/works/114514" ref='srcText'> <mdui-text-field variant="filled" label="链接 / 关键词" name="src">
<span v-if='err' slot="helper" class='warn-text'>链接格式错误!</span>
</mdui-text-field><br/> </mdui-text-field><br/>
<div style="display: flex"> <div style="display: flex">
<div style="flex-grow: 1"></div> <div style="flex-grow: 1"></div>
@ -78,4 +73,7 @@ function onConvert(data) {
<input type="submit" /> <input type="submit" />
</template></ClientOnly></Form> </template></ClientOnly></Form>
</section> </section>
<Hr/>
<Intro />
</template> </template>

View File

@ -0,0 +1,62 @@
<script setup>
import { ref, onMounted, onServerPrefetch } from 'vue'
import { useRoute } from 'vue-router'
import 'mdui/components/text-field.js'
import 'mdui/components/card.js'
import { escapeAndFormatText } from '../utils.js'
import { useSimpleSearchState } from '../stores/search.js'
const route = useRoute()
const inputField = ref('')
const simpleSearchState = useSimpleSearchState()
onServerPrefetch(async () => {
if (route.query.keyword) {
await simpleSearchState.start(route.query.keyword)
}
console.log(simpleSearchState.result[0])
})
onMounted(() => {
inputField.value = route.query.keyword || ''
if (inputField.value && simpleSearchState != 'ssrready') simpleSearchState.start(inputField.value)
})
function onSubmit(data) {
if (simpleSearchState) simpleSearchState.start(data.src)
}
</script>
<template>
<h1>搜索</h1>
<Form @submit="onSubmit"><ClientOnly>
<mdui-text-field variant="filled" :value="inputField" label="链接 / 关键词" name="src">
</mdui-text-field><br/>
<div style="display: flex">
<div style="flex-grow: 1"></div>
<mdui-button type="submit">-></mdui-button>
</div>
<template #ssr>
<input type="text" id="src" name="src" />
<input type="submit" />
</template></ClientOnly></Form><Hr />
<p>State: {{ simpleSearchState.state }}</p><Hr/>
<template v-if="simpleSearchState.result" v-for="work in simpleSearchState.result" :key="work.workId">
<ClientOnly><mdui-card style="margin: 8px 0px;"><article>
<router-link :to="`/work/${work.workId}`"><h3>{{ work.title }}</h3></router-link>
<h4>{{ work.pseud }}</h4>
<Hr />
<p v-html="escapeAndFormatText(work.summary)"></p>
</article></mdui-card><template #ssr>
<router-link :to="`/work/${work.workId}`"><h3>{{ work.title }}</h3></router-link>
<h4>{{ work.pseud }}</h4>
<p>{{ work.summary }}</p>
<Hr />
</template></ClientOnly>
</template>
</template>

View File

@ -168,8 +168,8 @@ onBeforeUnmount(() => {
<a @click="$router.back()">返回</a> <a @click="$router.back()">返回</a>
</template> </template>
<template v-if="workReadState.state == 'ready'"> <template v-if="workReadState.state == 'ready'">
<h1>{{ workReadState.title }}</h1> <h2>{{ workReadState.title }}</h2>
<h2>{{ workReadState.pesud }}</h2> <h4>{{ workReadState.pesud }}</h4>
<dl> <dl>
<template v-if="workReadState.category"><dt>作品圈</dt><ul> <template v-if="workReadState.category"><dt>作品圈</dt><ul>
<li v-for="item in workReadState.category" :key="item"> <li v-for="item in workReadState.category" :key="item">