diff --git a/cwd-admin/src/api/admin.ts b/cwd-admin/src/api/admin.ts index b20cd63..42b4e85 100644 --- a/cwd-admin/src/api/admin.ts +++ b/cwd-admin/src/api/admin.ts @@ -23,6 +23,7 @@ export type CommentItem = { likes?: number; ua?: string | null; isAdmin?: boolean; + siteId?: string; }; export type CommentListResponse = { @@ -115,8 +116,8 @@ export type VisitPagesResponse = { itemsByLatest?: VisitPageItem[]; }; -export type DomainListResponse = { - domains: string[]; +export type SiteListResponse = { + sites: string[]; }; export type LikeStatsItem = { @@ -153,11 +154,11 @@ export function logoutAdmin(): void { localStorage.removeItem('cwd_admin_token'); } -export function fetchComments(page: number, domain?: string): Promise { +export function fetchComments(page: number, siteId?: string): Promise { const searchParams = new URLSearchParams(); searchParams.set('page', String(page)); - if (domain) { - searchParams.set('domain', domain); + if (siteId && siteId !== 'default') { + searchParams.set('siteId', siteId); } return get(`/admin/comments/list?${searchParams.toString()}`); } @@ -262,8 +263,13 @@ export function blockEmail(email: string): Promise<{ message: string }> { return post<{ message: string }>('/admin/comments/block-email', { email }); } -export function exportComments(): Promise { - return get('/admin/comments/export'); +export function exportComments(siteId?: string): Promise { + const searchParams = new URLSearchParams(); + if (siteId && siteId !== 'default') { + searchParams.set('siteId', siteId); + } + const query = searchParams.toString(); + return get(query ? `/admin/comments/export?${query}` : '/admin/comments/export'); } export function importComments(data: any[]): Promise<{ message: string }> { @@ -278,8 +284,13 @@ export function importConfig(data: any[]): Promise<{ message: string }> { return post<{ message: string }>('/admin/import/config', data); } -export function exportStats(): Promise { - return get('/admin/export/stats'); +export function exportStats(siteId?: string): Promise { + const searchParams = new URLSearchParams(); + if (siteId && siteId !== 'default') { + searchParams.set('siteId', siteId); + } + const query = searchParams.toString(); + return get(query ? `/admin/export/stats?${query}` : '/admin/export/stats'); } export function importStats(data: any): Promise<{ message: string }> { @@ -294,30 +305,30 @@ export function importBackup(data: any): Promise<{ message: string }> { return post<{ message: string }>('/admin/import/backup', data); } -export function fetchCommentStats(domain?: string): Promise { +export function fetchCommentStats(siteId?: string): Promise { const searchParams = new URLSearchParams(); - if (domain) { - searchParams.set('domain', domain); + if (siteId && siteId !== 'default') { + searchParams.set('siteId', siteId); } const query = searchParams.toString(); const url = query ? `/admin/stats/comments?${query}` : '/admin/stats/comments'; return get(url); } -export function fetchVisitOverview(domain?: string): Promise { +export function fetchVisitOverview(siteId?: string): Promise { const searchParams = new URLSearchParams(); - if (domain) { - searchParams.set('domain', domain); + if (siteId && siteId !== 'default') { + searchParams.set('siteId', siteId); } const query = searchParams.toString(); const url = query ? `/admin/analytics/overview?${query}` : '/admin/analytics/overview'; return get(url); } -export function fetchVisitPages(domain?: string, order?: 'pv' | 'latest'): Promise { +export function fetchVisitPages(siteId?: string, order?: 'pv' | 'latest'): Promise { const searchParams = new URLSearchParams(); - if (domain) { - searchParams.set('domain', domain); + if (siteId && siteId !== 'default') { + searchParams.set('siteId', siteId); } if (order) { searchParams.set('order', order); @@ -327,8 +338,8 @@ export function fetchVisitPages(domain?: string, order?: 'pv' | 'latest'): Promi return get(url); } -export function fetchDomainList(): Promise { - return get('/admin/stats/domains'); +export function fetchSiteList(): Promise { + return get('/admin/stats/sites'); } export function fetchLikeStats(): Promise { diff --git a/cwd-admin/src/composables/useSite.ts b/cwd-admin/src/composables/useSite.ts new file mode 100644 index 0000000..1f6ce99 --- /dev/null +++ b/cwd-admin/src/composables/useSite.ts @@ -0,0 +1,17 @@ +import { ref, watch } from 'vue'; + +const currentSiteId = ref(localStorage.getItem('cwd_admin_site_id') || 'default'); + +watch(currentSiteId, (val) => { + if (val) { + localStorage.setItem('cwd_admin_site_id', val); + } else { + localStorage.removeItem('cwd_admin_site_id'); + } +}); + +export function useSite() { + return { + currentSiteId + }; +} diff --git a/cwd-admin/src/views/AnalyticsVisitView/index.vue b/cwd-admin/src/views/AnalyticsVisitView/index.vue index 6cb5504..5fe228f 100644 --- a/cwd-admin/src/views/AnalyticsVisitView/index.vue +++ b/cwd-admin/src/views/AnalyticsVisitView/index.vue @@ -224,6 +224,7 @@ import { fetchLikeStats, type LikeStatsItem, } from "../../api/admin"; +import { useSite } from "../../composables/useSite"; const loading = ref(false); const listLoading = ref(false); @@ -240,6 +241,8 @@ const overview = ref({ last30Days: [], }); +const { currentSiteId } = useSite(); + function calculateChange(current: number, previous: number) { if (previous === 0) { return current > 0 ? 100 : 0; @@ -271,8 +274,6 @@ const visitTab = ref<"pv" | "latest">("pv"); const visitTabStorageKey = "cwd-analytics-visit-tab"; const chartRangeStorageKey = "cwd-analytics-visit-chart-range"; -const injectedDomainFilter = inject | null>("domainFilter", null); -const domainFilter = injectedDomainFilter ?? ref(""); const last30Days = ref<{ date: string; total: number }[]>([]); const likeStatsItems = ref([]); const chartRange = ref<"7" | "30">("7"); @@ -424,7 +425,7 @@ async function loadData() { listLoading.value = true; error.value = ""; try { - const domain = domainFilter.value || undefined; + const domain = currentSiteId.value; const order = getVisitOrderParam(); const [overviewRes, pagesRes, likeStatsRes] = await Promise.all([ fetchVisitOverview(domain), @@ -589,7 +590,7 @@ onBeforeUnmount(() => { } }); -watch(domainFilter, () => { +watch(currentSiteId, () => { loadData(); }); diff --git a/cwd-admin/src/views/CommentsView/index.vue b/cwd-admin/src/views/CommentsView/index.vue index 19ebb78..c215d41 100644 --- a/cwd-admin/src/views/CommentsView/index.vue +++ b/cwd-admin/src/views/CommentsView/index.vue @@ -240,9 +240,9 @@ import { updateComment, blockIp, blockEmail, - fetchDomainList, } from "../../api/admin"; import ModalEdit from "./components/ModalEdit.vue"; +import { useSite } from "../../composables/useSite"; const route = useRoute(); const router = useRouter(); @@ -252,8 +252,7 @@ const pagination = ref<{ page: number; total: number }>({ page: 1, total: 1 }); const loading = ref(false); const error = ref(""); const statusFilter = ref(""); -const injectedDomainFilter = inject | null>("domainFilter", null); -const domainFilter = injectedDomainFilter ?? ref(""); +const { currentSiteId } = useSite(); const jumpPageInput = ref(""); const editVisible = ref(false); const editSaving = ref(false); @@ -325,7 +324,7 @@ async function loadComments(page?: number) { loading.value = true; error.value = ""; try { - const res = await fetchComments(targetPage, domainFilter.value || undefined); + const res = await fetchComments(targetPage, currentSiteId.value); comments.value = res.data; pagination.value = { page: res.pagination.page, total: res.pagination.total }; } catch (e: any) { @@ -342,11 +341,9 @@ function updateRoutePage(page: number) { } else { query.p = String(page); } - if (domainFilter.value) { - query.domain = domainFilter.value; - } else { - delete query.domain; - } + // Removed domain from query as it's now global state + delete query.domain; + router.push({ query }); } @@ -530,15 +527,11 @@ onMounted(() => { initialPage = Math.floor(value); } } - const d = route.query.domain; - if (typeof d === "string" && d.trim()) { - domainFilter.value = d.trim(); - } loadComments(initialPage); }); -watch(domainFilter, () => { +watch(currentSiteId, () => { updateRoutePage(1); loadComments(1); }); diff --git a/cwd-admin/src/views/DataView/index.vue b/cwd-admin/src/views/DataView/index.vue index 79027e4..54835be 100644 --- a/cwd-admin/src/views/DataView/index.vue +++ b/cwd-admin/src/views/DataView/index.vue @@ -121,6 +121,7 @@ import { exportStats, importStats, exportBackup, importBackup } from "../../api/admin"; +import { useSite } from "../../composables/useSite"; const exporting = ref(false); const importing = ref(false); @@ -130,6 +131,7 @@ const toastMessage = ref(""); const toastType = ref<"success" | "error">("success"); const toastVisible = ref(false); const importLogs = ref([]); +const { currentSiteId } = useSite(); // 当前导入模式: comments | config | stats | backup const currentImportMode = ref('comments'); @@ -178,9 +180,9 @@ async function executeExport(apiFunc: () => Promise, fileNamePrefix: string } // 导出处理 -const handleExportComments = () => executeExport(exportComments, 'comments-export'); +const handleExportComments = () => executeExport(() => exportComments(currentSiteId.value), 'comments-export'); const handleExportConfig = () => executeExport(exportConfig, 'cwd-config'); -const handleExportStats = () => executeExport(exportStats, 'cwd-stats'); +const handleExportStats = () => executeExport(() => exportStats(currentSiteId.value), 'cwd-stats'); const handleExportBackup = () => executeExport(exportBackup, 'cwd-full-backup'); // 触发文件选择 diff --git a/cwd-admin/src/views/LayoutView/index.vue b/cwd-admin/src/views/LayoutView/index.vue index ceb7292..71a3ce0 100644 --- a/cwd-admin/src/views/LayoutView/index.vue +++ b/cwd-admin/src/views/LayoutView/index.vue @@ -12,10 +12,10 @@
{{ layoutTitle }}
- + +
@@ -70,10 +70,10 @@ :class="{ 'layout-sider-mobile-open': isMobileSiderOpen }" >
- + +
@@ -171,19 +171,20 @@