feat: add API tab to about page

This commit is contained in:
Tim
2025-09-09 15:04:49 +08:00
parent 38ee37d5be
commit da311806c1

View File

@@ -1,23 +1,47 @@
<template> <template>
<div class="about-page"> <div class="about-page">
<BaseTabs v-model="selectedTab" :tabs="tabs"> <BaseTabs v-model="selectedTab" :tabs="tabs">
<div class="about-loading" v-if="isFetching"> <template v-if="selectedTab === 'api'">
<l-hatch-spinner size="100" stroke="10" speed="1" color="var(--primary-color)" /> <div class="about-api">
</div> <div v-if="!authState.loggedIn" class="about-api-login">
<div <NuxtLink to="/login">登录</NuxtLink>后查看 Token
v-else </div>
class="about-content" <div v-else class="about-api-token">
v-html="renderMarkdown(content)" <div class="token-row">
@click="handleContentClick" <span class="token-text">{{ token }}</span>
></div> <button class="copy-btn" @click="copyToken">复制</button>
</div>
<div class="token-warning">请不要将 Token 泄露给他人</div>
</div>
<div class="about-api-link">
<a href="https://docs.open-isle.com" target="_blank" rel="noopener noreferrer"
>API Playground</a
>
</div>
</div>
</template>
<template v-else>
<div class="about-loading" v-if="isFetching">
<l-hatch-spinner size="100" stroke="10" speed="1" color="var(--primary-color)" />
</div>
<div
v-else
class="about-content"
v-html="renderMarkdown(content)"
@click="handleContentClick"
></div>
</template>
</BaseTabs> </BaseTabs>
</div> </div>
</template> </template>
<script> <script>
import { onMounted, ref, watch } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from '#imports'
import { authState, getToken } from '~/utils/auth'
import { handleMarkdownClick, renderMarkdown } from '~/utils/markdown' import { handleMarkdownClick, renderMarkdown } from '~/utils/markdown'
import BaseTabs from '~/components/BaseTabs.vue' import BaseTabs from '~/components/BaseTabs.vue'
import { toast } from '~/composables/useToast'
export default { export default {
name: 'AboutPageView', name: 'AboutPageView',
@@ -44,11 +68,19 @@ export default {
label: '隐私政策', label: '隐私政策',
file: 'https://openisle-1307107697.cos.ap-guangzhou.myqcloud.com/assert/about/privacy.md', file: 'https://openisle-1307107697.cos.ap-guangzhou.myqcloud.com/assert/about/privacy.md',
}, },
{
key: 'api',
label: 'API与调试',
},
] ]
const route = useRoute()
const router = useRouter()
const selectedTab = ref(tabs[0].key) const selectedTab = ref(tabs[0].key)
const content = ref('') const content = ref('')
const token = computed(() => (authState.loggedIn ? getToken() : ''))
const loadContent = async (file) => { const loadContent = async (file) => {
if (!file) return
try { try {
isFetching.value = true isFetching.value = true
const res = await fetch(file) const res = await fetch(file)
@@ -65,19 +97,57 @@ export default {
} }
onMounted(() => { onMounted(() => {
loadContent(tabs[0].file) const initTab = route.query.tab
if (initTab && tabs.find((t) => t.key === initTab)) {
selectedTab.value = initTab
const tab = tabs.find((t) => t.key === initTab)
if (tab && tab.file) loadContent(tab.file)
} else {
loadContent(tabs[0].file)
}
}) })
watch(selectedTab, (name) => { watch(selectedTab, (name) => {
const tab = tabs.find((t) => t.key === name) const tab = tabs.find((t) => t.key === name)
if (tab) loadContent(tab.file) if (tab && tab.file) loadContent(tab.file)
router.replace({ query: { ...route.query, tab: name } })
}) })
watch(
() => route.query.tab,
(name) => {
if (name && name !== selectedTab.value && tabs.find((t) => t.key === name)) {
selectedTab.value = name
}
},
)
const copyToken = async () => {
if (import.meta.client && token.value) {
try {
await navigator.clipboard.writeText(token.value)
toast.success('已复制 Token')
} catch (e) {
toast.error('复制失败')
}
}
}
const handleContentClick = (e) => { const handleContentClick = (e) => {
handleMarkdownClick(e) handleMarkdownClick(e)
} }
return { tabs, selectedTab, content, renderMarkdown, isFetching, handleContentClick } return {
tabs,
selectedTab,
content,
renderMarkdown,
isFetching,
handleContentClick,
authState,
token,
copyToken,
}
}, },
} }
</script> </script>
@@ -101,6 +171,33 @@ export default {
height: 200px; height: 200px;
} }
.about-api {
padding: 20px;
}
.token-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
word-break: break-all;
}
.copy-btn {
padding: 4px 8px;
cursor: pointer;
}
.token-warning {
color: var(--danger-color);
margin-bottom: 20px;
}
.about-api-link a {
color: var(--primary-color);
text-decoration: underline;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.about-tabs { .about-tabs {
width: 100vw; width: 100vw;