mirror of
https://github.com/RhenCloud/Cloud-Home.git
synced 2026-01-22 17:39:07 +08:00
feat: 添加 Umami 分析支持,更新配置文档
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted } from "vue";
|
||||
import PageSwitcher from "./components/PageSwitcher.vue";
|
||||
import FooterSection from "./components/FooterSection.vue";
|
||||
import siteConfig from "./config/siteConfig";
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
<p class="muted" v-if="showHitokoto && quote">
|
||||
「{{ quote }}」<span v-if="from" class="from">—— {{ from }}</span>
|
||||
</p>
|
||||
<p class="muted stats" v-if="showStats && !statsError">
|
||||
👁️ {{ visitors }} visitors · 📊 {{ pageviews }} pageviews
|
||||
</p>
|
||||
<!-- <p class="muted stats" v-if="showStats && statsError">🔒 由于启用了隐私保护拓展,禁用状态统计</p> -->
|
||||
<p class="muted beian" v-if="contact.beian">
|
||||
<a :href="contact.beianLink || 'https://beian.miit.gov.cn/'" target="_blank" rel="noreferrer">
|
||||
{{ contact.beian }}
|
||||
@@ -14,14 +18,19 @@
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import siteConfig from "../config/siteConfig";
|
||||
const props = defineProps({ contact: Object });
|
||||
const quote = ref("");
|
||||
const from = ref("");
|
||||
const showHitokoto = props.contact?.showHitokoto !== false;
|
||||
const pageviews = ref(0);
|
||||
const visitors = ref(0);
|
||||
const statsError = ref(true);
|
||||
const showHitokoto = siteConfig.footer?.hitokoto?.enable;
|
||||
const showStats = ref(siteConfig.umami?.enable);
|
||||
|
||||
const buildHitokotoUrl = () => {
|
||||
const type = siteConfig.footer?.hitokoto?.type;
|
||||
const url = new URL("https://v1.hitokoto.cn/");
|
||||
const type = props.contact?.hitokotoType;
|
||||
if (Array.isArray(type)) {
|
||||
type.filter(Boolean).forEach((t) => url.searchParams.append("c", t));
|
||||
} else if (typeof type === "string") {
|
||||
@@ -44,8 +53,52 @@ const fetchHitokoto = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
const fetchStats = async () => {
|
||||
try {
|
||||
if (!siteConfig.umami?.apiBase || !siteConfig.umami?.websiteId) {
|
||||
return;
|
||||
}
|
||||
const apiBase = siteConfig.umami.apiBase;
|
||||
const websiteId = siteConfig.umami.websiteId;
|
||||
const apiKey = import.meta.env.VITE_UMAMI_API_KEY;
|
||||
|
||||
if (!apiKey) return;
|
||||
|
||||
// 获取统计数据
|
||||
const endAt = Date.now();
|
||||
const startAt = new Date(siteConfig.siteMeta.startDate).getTime();
|
||||
|
||||
const resp = await fetch(`${apiBase}/v1/websites/${websiteId}/stats?startAt=${startAt}&endAt=${endAt}`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
console.warn(`Stats API returned ${resp.status}`);
|
||||
statsError.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await resp.json();
|
||||
if (data) {
|
||||
statsError.value = false;
|
||||
pageviews.value = data.pageviews;
|
||||
visitors.value = data.visitors;
|
||||
}
|
||||
|
||||
if (pageviews.value === 0 && visitors.value === 0) {
|
||||
showStats.value = false;
|
||||
}
|
||||
} catch (e) {
|
||||
statsError.value = true;
|
||||
console.debug("Stats fetch failed (this is normal if blocked by ad blocker):", e.message);
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (showHitokoto) fetchHitokoto();
|
||||
if (showStats.value) fetchStats();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -54,14 +107,17 @@ onMounted(() => {
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.from {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.beian {
|
||||
font-size: 12px;
|
||||
margin: 6px 0;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
|
||||
.beian a {
|
||||
color: inherit;
|
||||
opacity: 0.85;
|
||||
@@ -69,12 +125,20 @@ onMounted(() => {
|
||||
border-radius: 8px;
|
||||
transition: color 0.2s ease, background 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.beian a:hover {
|
||||
color: var(--accent, #7cc1ff);
|
||||
background: rgba(124, 193, 255, 0.1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.custom-html {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.stats {
|
||||
font-size: 12px;
|
||||
margin: 6px 0;
|
||||
letter-spacing: 0.2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,60 +1,4 @@
|
||||
interface SiteConfig {
|
||||
profile: {
|
||||
name: string;
|
||||
title: string;
|
||||
avatar: string;
|
||||
bio: string;
|
||||
birthday?: string;
|
||||
gender?: string;
|
||||
pronouns?: string;
|
||||
location?: string;
|
||||
};
|
||||
socialLinks: Array<{
|
||||
name: string;
|
||||
url: string;
|
||||
}>;
|
||||
github: {
|
||||
username: string;
|
||||
};
|
||||
about: Array<{
|
||||
title: string;
|
||||
desc: string;
|
||||
icon: string;
|
||||
}>;
|
||||
siteMeta: {
|
||||
title: string;
|
||||
icon: string;
|
||||
};
|
||||
skills: Array<{
|
||||
title: string;
|
||||
items: string[];
|
||||
}>;
|
||||
sites: Array<{
|
||||
name: string;
|
||||
desc: string;
|
||||
url: string;
|
||||
}>;
|
||||
projects: Array<{
|
||||
name: string;
|
||||
url: string;
|
||||
desc: string;
|
||||
}>;
|
||||
friends: Array<{
|
||||
name: string;
|
||||
desc: string;
|
||||
url: string;
|
||||
avatar: string;
|
||||
}>;
|
||||
footer: {
|
||||
beian: string;
|
||||
beianLink: string;
|
||||
showHitokoto: boolean;
|
||||
hitokotoType: string;
|
||||
customHtml: string;
|
||||
};
|
||||
}
|
||||
|
||||
const siteConfig: SiteConfig = {
|
||||
const siteConfig = {
|
||||
profile: {
|
||||
name: "RhenCloud",
|
||||
title: "I'm RhenCloud.",
|
||||
@@ -88,6 +32,14 @@ const siteConfig: SiteConfig = {
|
||||
siteMeta: {
|
||||
title: "RhenCloud",
|
||||
icon: "favicon.ico", // public/favicon.ico
|
||||
startDate: "2025-12-06",
|
||||
},
|
||||
|
||||
umami: {
|
||||
enable: true,
|
||||
url: "https://cloud.umami.is/script.js",
|
||||
websiteId: "ddcd51c3-ccc7-45e4-81e6-11567027f69b",
|
||||
apiBase: "https://api.umami.is",
|
||||
},
|
||||
|
||||
skills: [
|
||||
@@ -143,9 +95,11 @@ const siteConfig: SiteConfig = {
|
||||
footer: {
|
||||
beian: "津ICP备2025039003号-1",
|
||||
beianLink: "https://beian.miit.gov.cn/",
|
||||
showHitokoto: true,
|
||||
hitokotoType: "a&b&c&d&j",
|
||||
customHtml: '<span style="opacity:.8">© 2025 <a href="https://rhen.cloud">RhenCloud</a></span>',
|
||||
hitokoto: {
|
||||
enable: true,
|
||||
type: "a&b&c&d&j",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
11
src/main.ts
11
src/main.ts
@@ -1,6 +1,15 @@
|
||||
import { createApp } from "vue";
|
||||
import { VueUmamiPlugin } from "@jaseeey/vue-umami-plugin";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import "./styles.css";
|
||||
import siteConfig from "./config/siteConfig";
|
||||
|
||||
createApp(App).use(router).mount("#app");
|
||||
const app = createApp(App);
|
||||
|
||||
if (process.env.NODE_ENV !== "development") {
|
||||
if (siteConfig.umami?.enable) {
|
||||
app.use(VueUmamiPlugin({ websiteID: siteConfig.umami.websiteId, scriptSrc: siteConfig.umami.url, router }));
|
||||
}
|
||||
}
|
||||
app.use(router).mount("#app");
|
||||
|
||||
@@ -25,8 +25,6 @@ const github = reactive({
|
||||
// 修改此处:使用 VITE_ 前缀
|
||||
const githubToken = import.meta.env.VITE_GITHUB_TOKEN ?? "";
|
||||
|
||||
console.log(githubToken);
|
||||
|
||||
onMounted(() => {
|
||||
document.title = siteMeta.title;
|
||||
const link = document.querySelector("link[rel~='icon']") || document.createElement("link");
|
||||
|
||||
Reference in New Issue
Block a user