Files
Havline/web/src/views/AboutView.vue
T
2026-10-01 17:20:06 +08:00

204 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<PageHeader title="关于项目" description="查看 Havline 版本、源开源项目和技术信息">
<template #actions>
<n-button :loading="refreshing" @click="refreshVersion">
<template #icon><n-icon :component="RefreshOutline" /></template>
刷新版本信息
</n-button>
</template>
</PageHeader>
<div class="stats-row">
<StatCard label="当前版本" :value="`v${version}`" sub="来自 /api/version" tone="brand">
<template #icon><n-icon :component="CloudOutline" /></template>
</StatCard>
<StatCard label="源项目" :value="GITHUB_REPO" sub="上游开源项目地址" tone="blue" value-small>
<template #icon><n-icon :component="LogoGithub" /></template>
</StatCard>
<StatCard label="开源协议" value="GPL-3.0" sub="GNU General Public License" tone="green">
<template #icon><n-icon :component="DocumentTextOutline" /></template>
</StatCard>
<StatCard label="运行状态" value="正常" sub="Havline 服务运行中" tone="teal">
<template #icon><n-icon :component="CheckmarkCircleOutline" /></template>
</StatCard>
</div>
<HavlineCard title="项目信息" subtitle="当前版本、项目定位和最近检查时间">
<div class="about-grid">
<div class="about-item">
<label>项目名称</label>
<strong>Havline</strong>
</div>
<div class="about-item">
<label>项目定位</label>
<span>面向 NAS 的轻量公网访问管理工具</span>
</div>
<div class="about-item">
<label>当前版本</label>
<span class="mono">v{{ version }}</span>
</div>
<div class="about-item">
<label>最近检查</label>
<span>{{ checkedAt || '刚刚' }}</span>
</div>
</div>
<div class="about-links">
<a :href="GITHUB_REPO_URL" target="_blank" rel="noopener noreferrer">
<n-icon :component="LogoGithub" />
源项目:{{ GITHUB_REPO }}
</a>
<a :href="GPL_URL" target="_blank" rel="noopener noreferrer">
<n-icon :component="DocumentTextOutline" />
查看 GPL-3.0 协议
</a>
</div>
</HavlineCard>
<HavlineCard title="源项目与开源说明" subtitle="Havline 的源项目地址保持不变">
<div class="about-copy">
<p>
Havline 的源开源项目为
<a :href="GITHUB_REPO_URL" target="_blank" rel="noopener noreferrer">{{ GITHUB_REPO }}</a>。
该地址用于查阅上游代码、提交记录和 Release 信息。
</p>
<p>
本项目继续采用
<a :href="GPL_URL" target="_blank" rel="noopener noreferrer">GPL-3.0</a>
开源。品牌名称调整不会改变原项目及其衍生版本的许可证义务。
</p>
</div>
</HavlineCard>
<HavlineCard title="技术栈" subtitle="Havline 当前使用的主要技术组件">
<div class="about-stack">
<span v-for="item in stack" :key="item">{{ item }}</span>
</div>
</HavlineCard>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { NButton, NIcon, useMessage } from 'naive-ui'
import {
CheckmarkCircleOutline,
CloudOutline,
DocumentTextOutline,
LogoGithub,
RefreshOutline,
} from '@vicons/ionicons5'
import { api } from '../api/client'
import HavlineCard from '../components/HavlineCard.vue'
import PageHeader from '../components/PageHeader.vue'
import StatCard from '../components/StatCard.vue'
import { GITHUB_REPO, GITHUB_REPO_URL } from '../constants/app'
import { formatDate } from '../utils/format'
const GPL_URL = 'https://www.gnu.org/licenses/gpl-3.0.html'
const message = useMessage()
const version = ref(__APP_VERSION__)
const checkedAt = ref('')
const refreshing = ref(false)
const stack = [
'Go 1.23',
'Vue 3',
'TypeScript',
'Vite',
'Naive UI',
'ECharts',
'SQLite',
'Nginx',
'FRP',
'Cloudflare Tunnel',
]
async function refreshVersion() {
refreshing.value = true
try {
const result = await api.getVersion()
version.value = result.version || version.value
checkedAt.value = formatDate(new Date().toISOString())
} catch (error) {
message.error(error instanceof Error ? error.message : '读取版本失败')
} finally {
refreshing.value = false
}
}
onMounted(() => {
void refreshVersion()
})
</script>
<style scoped>
.about-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: var(--havline-space-4);
}
.about-item {
min-width: 0;
padding: var(--havline-space-4);
border: 1px solid var(--havline-border);
border-radius: var(--havline-radius-sm);
background: var(--havline-bg);
}
.about-item label {
display: block;
margin-bottom: 6px;
color: var(--havline-text-muted);
font-size: 12px;
}
.about-item strong,
.about-item span {
color: var(--havline-text);
}
.about-links,
.about-stack {
display: flex;
flex-wrap: wrap;
gap: var(--havline-space-3);
margin-top: var(--havline-space-4);
}
.about-links a {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 10px;
color: var(--havline-brand-text);
border: 1px solid var(--havline-border);
border-radius: var(--havline-radius-sm);
background: var(--havline-surface);
text-decoration: none;
}
.about-copy {
display: grid;
gap: var(--havline-space-3);
color: var(--havline-text-secondary);
}
.about-copy p {
margin: 0;
}
.about-copy a {
color: var(--havline-brand-text);
text-decoration: none;
}
.about-stack span {
padding: 6px 10px;
color: var(--havline-text-secondary);
border: 1px solid var(--havline-border);
border-radius: 999px;
background: var(--havline-bg);
font-size: 12px;
}
</style>