feat(admin): 添加域名列表获取功能用于筛选
新增获取域名列表的API端点,用于统一管理评论和访问统计中的域名筛选功能。修改了前端多个视图的域名获取逻辑,从原来的分散获取改为统一调用新接口,提高代码复用性和维护性。 docs: 添加反馈页面并更新侧边栏
This commit is contained in:
@@ -107,6 +107,10 @@ export type VisitPagesResponse = {
|
||||
items: VisitPageItem[];
|
||||
};
|
||||
|
||||
export type DomainListResponse = {
|
||||
domains: string[];
|
||||
};
|
||||
|
||||
export async function loginAdmin(name: string, password: string): Promise<string> {
|
||||
const res = await post<AdminLoginResponse>('/admin/login', { name, password });
|
||||
const key = res.data.key;
|
||||
@@ -265,3 +269,7 @@ export function fetchVisitPages(domain?: string, order?: 'pv' | 'latest'): Promi
|
||||
const url = query ? `/admin/analytics/pages?${query}` : '/admin/analytics/pages';
|
||||
return get<VisitPagesResponse>(url);
|
||||
}
|
||||
|
||||
export function fetchDomainList(): Promise<DomainListResponse> {
|
||||
return get<DomainListResponse>('/admin/stats/domains');
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<h3 class="card-title">最近 30 天访问趋势</h3>
|
||||
<div v-if="loading" class="page-hint">加载中...</div>
|
||||
<div v-else-if="error" class="page-error">{{ error }}</div>
|
||||
<div v-else class="chart-wrapper">
|
||||
<div class="chart-wrapper">
|
||||
<div ref="chartEl" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,6 +127,7 @@ import * as echarts from "echarts";
|
||||
import {
|
||||
fetchVisitOverview,
|
||||
fetchVisitPages,
|
||||
fetchDomainList,
|
||||
type VisitOverviewResponse,
|
||||
type VisitPageItem,
|
||||
} from "../api/admin";
|
||||
@@ -252,20 +253,6 @@ async function loadData() {
|
||||
last30Days.value = Array.isArray(overviewRes.last30Days)
|
||||
? overviewRes.last30Days
|
||||
: [];
|
||||
|
||||
const domains = new Set<string>();
|
||||
for (const item of items.value) {
|
||||
const domainFromUrl =
|
||||
extractDomain(item.postUrl) || extractDomain(item.postSlug);
|
||||
if (domainFromUrl) {
|
||||
domains.add(domainFromUrl);
|
||||
}
|
||||
}
|
||||
const options = Array.from(domains);
|
||||
if (domainFilter.value && !options.includes(domainFilter.value)) {
|
||||
options.unshift(domainFilter.value);
|
||||
}
|
||||
domainOptions.value = options;
|
||||
} catch (e: any) {
|
||||
const msg = e.message || "加载访问统计数据失败";
|
||||
error.value = msg;
|
||||
@@ -274,14 +261,27 @@ async function loadData() {
|
||||
loading.value = false;
|
||||
listLoading.value = false;
|
||||
await nextTick();
|
||||
if (!error.value && last30Days.value.length > 0) {
|
||||
if (!error.value) {
|
||||
renderChart();
|
||||
} else if (chartInstance) {
|
||||
chartInstance.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDomains() {
|
||||
try {
|
||||
const res = await fetchDomainList();
|
||||
const domains = Array.isArray(res.domains) ? res.domains : [];
|
||||
const set = new Set(domains);
|
||||
if (domainFilter.value && !set.has(domainFilter.value)) {
|
||||
set.add(domainFilter.value);
|
||||
}
|
||||
domainOptions.value = Array.from(set);
|
||||
} catch (e: any) {
|
||||
const msg = e.message || "加载域名列表失败";
|
||||
showToast(msg, "error");
|
||||
}
|
||||
}
|
||||
|
||||
async function loadVisitPagesOnly() {
|
||||
listLoading.value = true;
|
||||
error.value = "";
|
||||
@@ -370,6 +370,7 @@ function handleResize() {
|
||||
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
loadDomains();
|
||||
window.addEventListener("resize", handleResize);
|
||||
});
|
||||
|
||||
|
||||
@@ -257,12 +257,12 @@ import {
|
||||
CommentItem,
|
||||
CommentListResponse,
|
||||
fetchComments,
|
||||
fetchCommentStats,
|
||||
deleteComment,
|
||||
updateCommentStatus,
|
||||
updateComment,
|
||||
blockIp,
|
||||
blockEmail,
|
||||
fetchDomainList,
|
||||
} from "../api/admin";
|
||||
|
||||
const DOMAIN_STORAGE_KEY = "cwd_admin_domain_filter";
|
||||
@@ -558,11 +558,9 @@ onMounted(() => {
|
||||
domainFilter.value = d.trim();
|
||||
}
|
||||
|
||||
fetchCommentStats()
|
||||
.then((res: CommentListResponse | any) => {
|
||||
const domains = Array.isArray(res.domains)
|
||||
? res.domains.map((item: any) => item.domain)
|
||||
: [];
|
||||
fetchDomainList()
|
||||
.then((res) => {
|
||||
const domains = Array.isArray(res.domains) ? res.domains : [];
|
||||
domainOptions.value = Array.from(new Set(domains));
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<h3 class="card-title">最近 30 天评论数趋势</h3>
|
||||
<div v-if="statsLoading" class="page-hint">加载中...</div>
|
||||
<div v-else-if="statsError" class="page-error">{{ statsError }}</div>
|
||||
<div v-else class="chart-wrapper">
|
||||
<div class="chart-wrapper">
|
||||
<div ref="chartEl" class="chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,7 +94,7 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onBeforeUnmount, ref, nextTick, watch } from "vue";
|
||||
import * as echarts from "echarts";
|
||||
import { fetchCommentStats } from "../api/admin";
|
||||
import { fetchCommentStats, fetchDomainList } from "../api/admin";
|
||||
|
||||
type DomainStat = {
|
||||
domain: string;
|
||||
@@ -152,14 +152,6 @@ async function loadStats() {
|
||||
rejected: res.summary.rejected,
|
||||
};
|
||||
domainStats.value = res.domains;
|
||||
const domains = Array.isArray(res.domains)
|
||||
? res.domains.map((item) => item.domain)
|
||||
: [];
|
||||
const set = new Set(domains);
|
||||
if (domainFilter.value && !set.has(domainFilter.value)) {
|
||||
set.add(domainFilter.value);
|
||||
}
|
||||
domainOptions.value = Array.from(set);
|
||||
last7Days.value = Array.isArray(res.last7Days) ? res.last7Days : [];
|
||||
} catch (e: any) {
|
||||
const msg = e.message || "加载统计数据失败";
|
||||
@@ -168,14 +160,27 @@ async function loadStats() {
|
||||
} finally {
|
||||
statsLoading.value = false;
|
||||
await nextTick();
|
||||
if (!statsError.value && last7Days.value.length > 0) {
|
||||
if (!statsError.value) {
|
||||
renderChart();
|
||||
} else if (chartInstance) {
|
||||
chartInstance.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDomains() {
|
||||
try {
|
||||
const res = await fetchDomainList();
|
||||
const domains = Array.isArray(res.domains) ? res.domains : [];
|
||||
const set = new Set(domains);
|
||||
if (domainFilter.value && !set.has(domainFilter.value)) {
|
||||
set.add(domainFilter.value);
|
||||
}
|
||||
domainOptions.value = Array.from(set);
|
||||
} catch (e: any) {
|
||||
const msg = e.message || "加载域名列表失败";
|
||||
showToast(msg, "error");
|
||||
}
|
||||
}
|
||||
|
||||
function renderChart() {
|
||||
const el = chartEl.value;
|
||||
if (!el) {
|
||||
@@ -239,6 +244,7 @@ function handleResize() {
|
||||
|
||||
onMounted(() => {
|
||||
loadStats();
|
||||
loadDomains();
|
||||
window.addEventListener("resize", handleResize);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user