diff --git a/server/app.mjs b/server/app.mjs index 8c2c40d..fc80d07 100644 --- a/server/app.mjs +++ b/server/app.mjs @@ -261,6 +261,7 @@ export function createAdminApp(services) { const { listAdminSeoGeoPublicationCatalog } = await importMemind('mindspace-seo-geo-admin-catalog.mjs'); const startAt = Number(req.query.startAt); const endAt = Number(req.query.endAt); + const config = loadMindSpaceConfig ? await loadMindSpaceConfig(pool) : null; const result = await listAdminSeoGeoPublicationCatalog(pool, { page: Number(req.query.page) || 1, pageSize: Number(req.query.pageSize) || 20, @@ -270,6 +271,8 @@ export function createAdminApp(services) { endAt: Number.isFinite(endAt) ? endAt : null, search: typeof req.query.search === 'string' ? req.query.search.trim() : '', publicHost: process.env.H5_PUBLIC_BASE_URL?.replace(/^https?:\/\//, '').replace(/\/$/, '') || 'm.tkmind.cn', + env: process.env, + analyticsConfig: config?.analytics ?? {}, }); res.json(result); } catch (error) { diff --git a/src/admin/pages/SeoGeoAnalyticsPage.tsx b/src/admin/pages/SeoGeoAnalyticsPage.tsx index d543ac6..8c73459 100644 --- a/src/admin/pages/SeoGeoAnalyticsPage.tsx +++ b/src/admin/pages/SeoGeoAnalyticsPage.tsx @@ -54,7 +54,8 @@ export function SeoGeoAnalyticsPage() { const [startDate, setStartDate] = useState(initialRange.startDate); const [endDate, setEndDate] = useState(initialRange.endDate); const [search, setSearch] = useState(''); - const [sortBy, setSortBy] = useState('totalViews'); + const [searchInput, setSearchInput] = useState(''); + const [sortBy, setSortBy] = useState('publishedAt'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); const [page, setPage] = useState(1); const [rows, setRows] = useState([]); @@ -68,6 +69,7 @@ export function SeoGeoAnalyticsPage() { const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [openingUmami, setOpeningUmami] = useState(false); + const [umamiStatus, setUmamiStatus] = useState<{ available: boolean; reason: string } | null>(null); const pageCount = Math.max(1, Math.ceil(total / 20)); @@ -93,11 +95,13 @@ export function SeoGeoAnalyticsPage() { geoViews: 0, crawlerViews: 0, }); + setUmamiStatus(result.umami ?? null); } catch (err) { setError(err instanceof Error ? err.message : '加载 SEO/GEO 页面目录失败'); setRows([]); setTotal(0); setTotals({ totalViews: 0, seoViews: 0, geoViews: 0, crawlerViews: 0 }); + setUmamiStatus(null); } finally { setLoading(false); } @@ -107,6 +111,13 @@ export function SeoGeoAnalyticsPage() { void load(); }, [load]); + useEffect(() => { + const timer = window.setTimeout(() => { + setSearch(searchInput.trim()); + }, 300); + return () => window.clearTimeout(timer); + }, [searchInput]); + useEffect(() => { setPage(1); }, [startDate, endDate, search, sortBy, sortOrder]); @@ -127,7 +138,12 @@ export function SeoGeoAnalyticsPage() {

SEO / GEO 流量

- 列出全部在线页(含零流量页面),仅展示统计与 URL,不提供跳转访问。可收录 = 公开且未过期。SEO / GEO 来源按 referrer 域名归类;爬虫按 User-Agent 识别。 + 列出全部在线页(含零流量页面),仅展示统计与 URL,不提供跳转访问。可收录 = 公开且未过期。筛选期内 SEO / GEO 优先合并 Umami 埋点(MindSpace 直链);/u/ 发布链路与爬虫仍保留 MySQL 计数。 + {umamiStatus && !umamiStatus.available && umamiStatus.reason + ? ` 当前 Umami 未接入(${umamiStatus.reason}),MindSpace 直链流量可能偏低。` + : umamiStatus?.available + ? ' Umami 已接入。' + : ''}

@@ -156,20 +172,20 @@ export function SeoGeoAnalyticsPage() { 搜索标题 / 用户 / URL setSearch(e.target.value)} + value={searchInput} + placeholder="例如 john、daily-news、0917" + onChange={(e) => setSearchInput(e.target.value)} />