CodeBot Wiki 是一款基于大语言模型的智能文档生成工具,能够自动解析项目代码,生成结构清晰、内容专业的项目 Wiki。它不仅覆盖项目概览、核心模块、关键逻辑等信息,还支持交互式理解,更适合团队协作与持续迭代,是理解开源项目或内部系统的理想助手!

本期解读项目地址:https://github.com/umami-software/umami
项目概览
本项目是一个基于 Node.js 和 Next.js 构建的 Web 应用程序,主要用于网站分析和数据收集。它支持通过容器化部署(如 Docker 和 Podman)进行快速启动和管理,并提供了丰富的脚本工具用于构建、测试、部署和国际化支持。项目的核心功能包括环境变量检查、数据库连接验证、遥测数据发送、路由配置、语言文件处理等。
核心架构与组件
1. 容器化部署支持
项目支持通过 Docker 和 Podman 进行容器化部署,相关的配置文件包括:
cypress/docker-compose.yml
:用于运行 Cypress 测试的 Docker 环境,包含umami
、db
和cypress
三个服务。podman/podman-compose.yml
:用于 Podman 部署的配置文件,定义了umami
和db
两个服务。podman/umami.service
:systemd 服务配置文件,用于通过 Podman Compose 启动和管理 Umami 应用栈。podman/env.sample
:Podman 环境变量配置示例文件,用户需将其重命名为.env
并根据实际部署环境修改相应值。
容器化部署流程图

2. 环境变量与配置管理
项目通过多个脚本和配置文件来管理环境变量和配置:
scripts/check-env.js
:检查运行环境中是否缺少必要的环境变量,确保项目在启动前具备所有必要的环境配置。podman/env.sample
:提供连接到 PostgreSQL 数据库的连接字符串、数据库类型、应用程序密钥等配置项。scripts/start-env.js
:启动 Next.js 应用程序的开发或生产环境服务,通过dotenv
模块加载.env
文件中的环境变量。
环境变量检查流程图

3. 数据库连接与迁移
项目通过 Prisma 进行数据库连接和迁移管理:
scripts/check-db.js
:检查数据库连接、环境配置及版本兼容性,验证DATABASE_URL
是否定义、建立 Prisma 数据库连接、检查数据库版本是否符合最低要求、检测是否存在旧版 Umami v1 的迁移记录,并在必要时执行 Prisma 数据库迁移。scripts/copy-db-files.js
:根据当前环境配置中的数据库类型,将对应的数据库文件从源目录复制到目标目录。
数据库检查流程图

4. 国际化支持
项目支持多语言国际化,相关的脚本和文件包括:
scripts/download-language-names.js
:下载不同语言的名称列表文件,并将其保存到指定目录中。scripts/download-country-names.js
:从 GitHub 上的开源项目下载多语言国家名称数据文件,并将这些 JSON 文件保存到本地指定目录中。scripts/format-lang.js
:将src/lang
目录下的语言文件转换为适合format-js
使用的格式,并输出到build/messages
目录中。scripts/check-lang.js
:检查多语言文件中是否存在缺失或未翻译的键值对。scripts/merge-messages.js
:将从项目中提取的多语言消息与现有语言文件进行合并。
国际化处理流程图

5. 遥测与数据收集
项目通过遥测脚本收集运行环境信息,并发送到远程服务器:
scripts/telemetry.js
:实现了一个用于发送遥测数据的函数sendTelemetry(type)
,收集当前运行环境的信息(如 Node.js 版本、操作系统类型与版本、平台架构、是否为 Docker 容器或 CI 环境等),并将其以 JSON 格式通过 HTTP POST 请求发送到指定的远程 API 地址。scripts/postbuild.js
:在构建完成后执行某些操作,通过调用sendTelemetry('build')
函数发送与“构建”相关的遥测数据。
遥测数据发送流程图

6. 路由与静态资源管理
项目通过脚本动态修改 Next.js 的路由配置文件:
scripts/set-routes-manifest.js
:动态修改 Next.js 项目的路由配置文件(routes-manifest.json
),用于自定义 API 路由和静态资源的重写与头部设置。scripts/update-tracker.js
:读取并更新项目中用于数据追踪的 JavaScript 文件(public/script.js
)中的 API 端点。
路由配置流程图

遥测与数据收集机制深度分析
1. sendTelemetry 函数实现
通过分析 scripts/telemetry.js
文件,我们发现 sendTelemetry
函数是遥测数据收集与发送的核心实现:
const os = require('os');
const isCI = require('is-ci');
const pkg = require('../package.json');
const url = 'https://api.umami.is/v1/telemetry';
async function sendTelemetry(type) {
const { default: isDocker } = await import('is-docker');
const { default: fetch } = await import('node-fetch');
const data = {
type,
payload: {
version: pkg.version,
node: process.version,
platform: os.platform(),
arch: os.arch(),
os: `${os.type()} ${os.version()}`,
is_docker: isDocker(),
is_ci: isCI,
},
};
try {
await fetch(url, {
method: 'post',
cache: 'no-cache',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
} catch {
// Ignore
}
}
该函数收集以下环境信息:
- 应用版本 (
pkg.version
) - Node.js 版本 (
process.version
) - 操作系统平台 (
os.platform()
) - 系统架构 (
os.arch()
) - OS 类型和版本 (
os.type()
和os.version()
) - 是否在 Docker 环境中运行 (
isDocker()
) - 是否在 CI 环境中运行 (
isCI
)
2. 构建后遥测数据发送
在 scripts/postbuild.js
中,我们看到构建完成后如何触发遥测数据发送:
require('dotenv').config();
const { sendTelemetry } = require('./telemetry');
async function run() {
if (!process.env.DISABLE_TELEMETRY) {
await sendTelemetry('build');
}
}
run();
这个脚本会在构建完成后检查 DISABLE_TELEMETRY
环境变量,如果未设置或为假值,则调用 sendTelemetry('build')
发送构建相关的遥测数据。
3. 遥测功能控制机制
遥测功能通过环境变量 DISABLE_TELEMETRY
进行控制。当该变量被设置时,sendTelemetry
函数不会被调用,从而完全禁用遥测数据的发送。
4. 遥测数据发送目标
遥测数据被发送到固定的 URL:https://api.umami.is/v1/telemetry
,使用 POST 方法发送 JSON 格式的遥测数据。
主要功能与组件表
功能/组件 | 描述 |
---|---|
cypress/docker-compose.yml | 用于运行 Cypress 测试的 Docker 环境配置 |
podman/podman-compose.yml | 用于 Podman 部署的配置文件 |
podman/umami.service | systemd 服务配置文件,用于通过 Podman Compose 启动和管理 Umami 应用栈 |
scripts/check-env.js | 检查运行环境中是否缺少必要的环境变量 |
scripts/check-db.js | 检查数据库连接、环境配置及版本兼容性 |
scripts/download-language-names.js | 下载不同语言的名称列表文件 |
scripts/download-country-names.js | 下载多语言国家名称数据文件 |
scripts/format-lang.js | 将语言文件转换为适合 format-js 使用的格式 |
scripts/check-lang.js | 检查多语言文件中是否存在缺失或未翻译的键值对 |
scripts/merge-messages.js | 将提取的多语言消息与现有语言文件进行合并 |
scripts/telemetry.js | 发送遥测数据的函数 |
scripts/postbuild.js | 在构建完成后发送遥测数据 |
scripts/set-routes-manifest.js | 动态修改 Next.js 项目的路由配置文件 |
scripts/update-tracker.js | 更新项目中用于数据追踪的 JavaScript 文件中的 API 端点 |
结论
本项目通过容器化部署、环境变量管理、数据库连接与迁移、国际化支持、遥测与数据收集、路由与静态资源管理等多个模块,构建了一个功能完整、易于部署和维护的 Web 应用程序。每个模块都有明确的职责和功能,通过脚本和配置文件的协同工作,确保了项目的稳定性和可扩展性。特别是在遥测与数据收集方面,项目实现了灵活的控制机制,既保证了数据收集的完整性,又尊重了用户的隐私选择。
团队模块
简介
团队模块是项目中用于管理团队信息、成员和相关资源的核心功能模块。它通过 RESTful API 提供对团队的查看、更新、删除操作,以及对团队成员的增删改查和权限控制。此外,模块还支持用户通过访问码加入团队,以及对团队网站信息的分页查询。
该模块分为两个主要部分:API 接口层和服务于前端展示的页面组件层。API 接口层负责处理所有与团队相关的业务逻辑和数据交互,而页面组件层则提供了用户界面以展示和操作团队数据。
详细章节
API 接口层
团队管理接口
该接口位于 src/app/api/teams/[teamId]/route.ts
,提供对单个团队的管理功能。
- GET:获取团队信息,包括成员列表。
- 调用
getTeam(teamId, { includeMembers: true })
获取数据。 - 使用
canViewTeam(auth, teamId)
校验权限。 - POST:更新团队信息。
- 验证请求体字段。
- 调用
updateTeam(teamId, body)
更新数据。 - 使用
canUpdateTeam(auth, teamId)
校验权限。 - DELETE:删除团队。
- 使用
canDeleteTeam(auth, teamId)
校验权限。 - 调用
deleteTeam(teamId)
执行删除。
团队成员管理接口
团队用户列表接口
该接口位于 src/app/api/teams/[teamId]/users/route.ts
,用于管理团队中的用户列表。
- GET:获取团队用户列表。
- 验证权限并过滤无效数据。
- POST:添加新用户到团队。
- 校验权限和输入合法性。
- 创建用户与团队的关系记录。
特定用户管理接口
该接口位于 src/app/api/teams/[teamId]/users/[userId]/route.ts
,用于管理团队中的特定用户。
- GET:获取特定用户的详细信息。
- POST:更新特定用户的角色。
- DELETE:从团队中移除特定用户。
- 所有操作均包含权限校验和数据验证。
团队网站信息接口
该接口位于 src/app/api/teams/[teamId]/websites/route.ts
,用于查询团队关联的网站信息。
- GET:获取团队网站信息。
- 使用
zod
校验分页参数。 - 验证权限后调用
getTeamWebsites
查询数据库。 - 返回 JSON 格式的分页数据。
用户加入团队接口
该接口位于 src/app/api/teams/join/route.ts
,用于处理用户通过访问码加入团队的请求。
- POST:用户加入团队。
- 使用
zod
校验请求体中的accessCode
。 - 调用
parseRequest
验证数据和用户身份。 - 检查用户权限。
- 查询
accessCode
对应的团队。 - 若团队存在且用户未加入,则添加用户为成员。
页面组件层
团队成员管理页面
该页面位于 src/app/(main)/teams/[teamId]/settings/members/page.tsx
,是用于展示团队成员信息的 Next.js 页面组件。
- 导出异步默认函数组件。
- 接收
params
中的teamId
并传递给<TeamMembersPage />
渲染。 - 设置页面元数据标题为 “Team Members”。
团队成员编辑按钮
该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMemberEditButton.tsx
,是一个编辑按钮组件。
- 点击后弹出模态框显示
TeamMemberEditForm
表单。 - 接收
teamId
、userId
和role
参数。 - 通过回调处理保存逻辑。
- 使用多个自定义 Hook 实现国际化、提示和状态管理。
团队成员编辑表单
该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMemberEditForm.tsx
,是一个表单组件。
- 用于修改成员角色。
- 接收
teamId
、userId
和role
。 - 提交时调用 API 更新权限。
- 结合
useApi
和useMutation
处理请求与状态。 - 支持多语言标签。
团队成员移除按钮
该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMemberRemoveButton.tsx
,是一个删除成员按钮组件。
- 触发确认对话框并调用 API 删除用户。
- 使用
ModalTrigger
和ConfirmationForm
实现交互逻辑。 - 依赖多个 Hook 管理请求与状态更新。
团队成员数据表格容器
该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMembersDataTable.tsx
,是表格容器组件。
- 负责获取并展示团队成员数据。
- 通过
useTeamMembers(teamId)
获取数据。 - 渲染
DataTable
及其子组件TeamMembersTable
。 - 实现数据展示与交互分离。
团队成员页面组件
该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMembersPage.tsx
,是客户端页面组件。
- 根据用户权限决定是否允许编辑操作。
- 结合
TeamContext
、useLogin
和useMessages
控制界面行为。 - 渲染
TeamMembersDataTable
展示成员列表。
团队成员表格组件
该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMembersTable.tsx
,是表格组件。
- 展示成员信息并提供编辑和移除操作。
- 根据
allowEdit
条件渲染对应按钮。 - 禁止对团队所有者或当前用户进行操作。
- 使用
GridTable
构建结构。
Mermaid图
团队模块架构图

团队管理接口流程图

团队成员管理接口流程图

用户加入团队接口流程图

表格
主要功能或组件及其描述
功能/组件 | 描述 |
---|---|
团队管理接口 | 提供对单个团队的查看、更新、删除操作 |
团队成员管理接口 | 管理团队中的用户列表和特定用户 |
团队网站信息接口 | 查询团队关联的网站信息 |
用户加入团队接口 | 处理用户通过访问码加入团队的请求 |
团队成员管理页面 | 展示团队成员信息的 Next.js 页面组件 |
团队成员编辑按钮 | 编辑成员角色的按钮组件 |
团队成员编辑表单 | 修改成员角色的表单组件 |
团队成员移除按钮 | 删除成员的按钮组件 |
团队成员数据表格容器 | 获取并展示团队成员数据的容器组件 |
团队成员页面组件 | 客户端页面组件,控制界面行为 |
团队成员表格组件 | 展示成员信息并提供操作的表格组件 |
API 接口参数、类型和描述
接口 | 方法 | 参数 | 类型 | 描述 |
---|---|---|---|---|
/teams/{teamId} | GET | teamId | string | 团队ID |
/teams/{teamId} | POST | teamId, body | string, object | 团队ID, 请求体 |
/teams/{teamId} | DELETE | teamId | string | 团队ID |
/teams/{teamId}/users | GET | teamId | string | 团队ID |
/teams/{teamId}/users | POST | teamId, body | string, object | 团队ID, 请求体 |
/teams/{teamId}/users/{userId} | GET | teamId, userId | string, string | 团队ID, 用户ID |
/teams/{teamId}/users/{userId} | POST | teamId, userId, body | string, string, object | 团队ID, 用户ID, 请求体 |
/teams/{teamId}/users/{userId} | DELETE | teamId, userId | string, string | 团队ID, 用户ID |
/teams/{teamId}/websites | GET | teamId, query | string, object | 团队ID, 查询参数 |
/teams/join | POST | body | object | 请求体,包含accessCode |
权限校验函数
canViewTeam
def canViewTeam(auth, teamId):
# 校验用户是否有权限查看团队
pass
canUpdateTeam
def canUpdateTeam(auth, teamId):
# 校验用户是否有权限更新团队
pass
canDeleteTeam
def canDeleteTeam(auth, teamId):
# 校验用户是否有权限删除团队
pass
数据操作函数
getTeam
def getTeam(teamId, options):
# 获取团队信息
pass
updateTeam
def updateTeam(teamId, data):
# 更新团队信息
pass
deleteTeam
def deleteTeam(teamId):
# 删除团队
pass
结论/总结
团队模块是项目中一个关键的功能模块,它通过 API 接口层和服务于前端展示的页面组件层,实现了对团队信息、成员和相关资源的全面管理。该模块不仅提供了基础的 CRUD 操作,还包含了权限控制、数据验证和用户交互等高级功能,确保了团队管理的安全性和易用性。通过清晰的架构设计和组件划分,团队模块为项目的其他部分提供了稳定可靠的服务支持。
状态管理模块
简介
状态管理模块是项目中负责维护和管理全局状态的核心部分,基于 Zustand 实现。它涵盖了从应用配置、用户信息到特定功能模块(如仪表盘和网站)的状态管理。通过将状态集中存储和更新,模块确保了应用各组件之间的数据一致性与响应式更新能力。
详细章节
全局状态管理 (app.ts)
架构与功能
src/store/app.ts
文件实现了全局状态管理,维护语言、主题、时区、日期范围、分享令牌、用户信息和配置等状态。状态可从本地存储或环境变量加载,并提供设置函数用于动态更新。
关键函数与数据结构
setValue(key, value)
: 用于设置指定键值对的状态数据。- 状态字段包括
language
,theme
,timezone
,dateRange
,shareToken
,user
,config
等。
初始化逻辑
const initialState = {
locale: getItem(LOCALE_CONFIG) || process.env.defaultLocale || DEFAULT_LOCALE,
theme: getItem(THEME_CONFIG) || getDefaultTheme() || DEFAULT_THEME,
timezone: getItem(TIMEZONE_CONFIG) || getTimezone(),
dateRange: getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE,
shareToken: null,
user: null,
config: null,
};
基础状态写入能力 (cache.ts)
架构与功能
src/store/cache.ts
文件使用 Zustand 创建一个全局 store,提供基础的状态写入能力。
关键函数
setValue(key, value)
: 设置指定键值对的状态数据,供其他模块共享或持久化状态。
实现细节
export function setValue(key: string, value: any) {
store.setState({ [key]: value });
}
仪表盘状态管理 (dashboard.ts)
架构与功能
src/store/dashboard.ts
文件实现 Dashboard 模块的状态管理,包含图表显示控制、网站数量限制、排序与激活状态等配置项。
关键函数
saveDashboard(settings)
: 用于同步更新与保存到本地存储。
状态结构
export const initialState = {
showCharts: true,
limit: DEFAULT_WEBSITE_LIMIT,
websiteOrder: [],
websiteActive: [],
editing: false,
isEdited: false,
};
时间戳记录 (modified.ts)
架构与功能
src/store/modified.ts
文件创建一个记录时间戳的 store。
关键函数
touch(key)
: 将指定 key 与当前时间戳关联并更新至 store,用于标记事件或操作的最新发生时间。
实现细节
export function touch(key: string) {
store.setState({ [key]: Date.now() });
}
版本检查逻辑 (version.ts)
架构与功能
src/store/version.ts
文件管理应用版本检查逻辑,包括当前版本、最新版本、是否更新及发布链接等字段。
关键函数
checkVersion()
: 请求远程版本信息并比较,判断是否存在新版本并更新状态。
状态结构
const initialState = {
current: CURRENT_VERSION,
latest: null,
hasUpdate: false,
checked: false,
releaseUrl: null,
};
网站状态管理 (websites.ts)
架构与功能
src/store/websites.ts
文件使用 Zustand 和 Immer 管理网站相关的 dateRange
和 dateCompare
状态。
关键函数
setWebsiteDateRange
: 按网站 ID 更新对应配置并附加修改时间戳。setWebsiteDateCompare
: 按网站 ID 更新对应配置并附加修改时间戳。
实现细节
export function setWebsiteDateRange(websiteId: string, dateRange: DateRange) {
store.setState(
produce(state => {
if (!state[websiteId]) {
state[websiteId] = {};
}
state[websiteId].dateRange = { ...dateRange, modified: Date.now() };
return state;
}),
);
}
Mermaid图
状态管理模块关系图

表格
主要功能或组件及其描述
组件/功能 | 描述 |
---|---|
全局状态管理 | 维护语言、主题、时区、日期范围、分享令牌、用户信息和配置等状态 |
基础状态写入能力 | 提供基础的状态写入能力 |
仪表盘状态管理 | 实现 Dashboard 模块的状态管理 |
时间戳记录 | 记录事件或操作的最新发生时间 |
版本检查逻辑 | 管理应用版本检查逻辑 |
网站状态管理 | 管理网站相关的 dateRange 和 dateCompare 状态 |
状态字段详情
文件 | 状态字段 | 类型 | 描述 |
---|---|---|---|
app.ts | locale | string | 当前语言设置 |
app.ts | theme | string | 当前主题设置 |
app.ts | timezone | string | 当前时区设置 |
app.ts | dateRange | object | 当前日期范围 |
app.ts | shareToken | string/null | 分享令牌 |
app.ts | user | object/null | 用户信息 |
app.ts | config | object/null | 应用配置 |
dashboard.ts | showCharts | boolean | 是否显示图表 |
dashboard.ts | limit | number | 网站数量限制 |
dashboard.ts | websiteOrder | array | 网站排序 |
dashboard.ts | websiteActive | array | 激活的网站 |
dashboard.ts | editing | boolean | 是否处于编辑状态 |
dashboard.ts | isEdited | boolean | 是否已编辑 |
version.ts | current | string | 当前版本 |
version.ts | latest | string/null | 最新版本 |
version.ts | hasUpdate | boolean | 是否有更新 |
version.ts | checked | boolean | 是否已检查 |
version.ts | releaseUrl | string/null | 发布链接 |
结论/总结
状态管理模块通过 Zustand 实现了全局状态的集中管理,涵盖了从应用配置到特定功能模块的状态管理。通过提供基础的状态写入能力、仪表盘状态管理、时间戳记录、版本检查逻辑和网站状态管理,模块确保了应用各组件之间的数据一致性与响应式更新能力。这些模块协同工作,为整个应用提供了稳定、高效的状态管理解决方案。
UI组件库
简介
UI组件库是项目中用于构建用户界面的核心模块,涵盖了布局、输入控件和图表三大类组件。这些组件通过模块化的CSS和React实现,提供了高度可复用和可定制的UI元素,支持响应式设计和国际化。布局组件如Grid
、MenuLayout
和Page
提供了页面结构的基础;输入控件如DateFilter
、DownloadButton
和LanguageButton
增强了用户交互;图表组件如BarChart
、PieChart
和BubbleChart
则用于数据可视化。
布局组件
Grid
Grid
组件提供了一个基于CSS Grid的响应式布局系统。它包含Grid
容器和GridRow
行组件,支持多种列分配模式。
样式定义
.grid
:网格容器,使用网格布局。.row
:行,默认包含6列,.row.compare
提供特殊列宽配置。.col
:列样式,包括内边距、最小高度和左侧边框。
组件实现
Grid
:渲染带有自定义类名和样式的<div>
容器。GridRow
:根据columns
属性动态渲染子元素为带对应类名的列容器。
const Grid: React.FC<{ className?: string }> = ({ className, children }) => {
return <div className={classNames(styles.grid, className)}>{children}</div>;
};
const GridRow: React.FC<{ columns?: number }> = ({ columns = 6, children }) => {
return (
<div className={styles.row}>
{React.Children.map(children, (child) => (
<div className={styles.col}>{child}</div>
))}
</div>
);
};
MenuLayout
MenuLayout
组件用于构建侧边导航菜单布局,支持响应式设计。
样式定义
.layout
:使用CSS Grid实现两列布局。.menu
:固定宽度菜单区,设置内边距。.content
:主内容区,使用Flexbox实现垂直排列。
组件实现
MenuLayout
:接收items
和children
,通过usePathname
匹配当前路径并高亮菜单项。
const MenuLayout: React.FC<{ items: any[]; children: React.ReactNode }> = ({
items,
children,
}) => {
const pathname = usePathname();
return (
<div className={styles.layout}>
<div className={styles.menu}>
{items.map((item) => (
<div
key={item.key}
className={pathname === item.path ? styles.selected : ''}
>
{item.label}
</div>
))}
</div>
<div className={styles.content}>{children}</div>
</div>
);
};
Page
Page
组件用于页面级布局,支持错误和加载状态管理。
样式定义
.page
:页面容器,使用Flexbox实现垂直排列,设置最大宽度和内边距。
组件实现
Page
:接收className
、error
、isLoading
和children
,优先处理错误和加载状态。
const Page: React.FC<{
className?: string;
error?: string;
isLoading?: boolean;
children: React.ReactNode;
}> = ({ className, error, isLoading, children }) => {
if (error) return <Banner type="error">{error}</Banner>;
if (isLoading) return <Loading />;
return <div className={classNames(styles.page, className)}>{children}</div>;
};
输入控件
DateFilter
DateFilter
组件提供日期筛选功能,支持预设时间范围或自定义日期。
样式定义
.dropdown span
:防止文本换行。
组件实现
DateFilter
:接收startDate
、endDate
等属性,通过Dropdown
显示选项,点击“自定义”弹出Modal
和DatePickerForm
表单。
const DateFilter: React.FC<{
startDate?: Date;
endDate?: Date;
onChange: (start: Date, end: Date) => void;
}> = ({ startDate, endDate, onChange }) => {
const [showCustom, setShowCustom] = useState(false);
return (
<>
<Dropdown>
<span onClick={() => setShowCustom(true)}>自定义</span>
</Dropdown>
{showCustom && (
<Modal>
<DatePickerForm
startDate={startDate}
endDate={endDate}
onSubmit={onChange}
/>
</Modal>
)}
</>
);
};
DownloadButton
DownloadButton
组件将数据转为CSV并下载。
组件实现
DownloadButton
:接收filename
和data
属性,结合TooltipPopup
提示用户,并在无数据时禁用按钮。
const DownloadButton: React.FC<{ filename: string; data: any[] }> = ({
filename,
data,
}) => {
const handleClick = () => {
const csv = Papa.unparse(data);
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.click();
};
return (
<TooltipPopup content="下载数据">
<button onClick={handleClick} disabled={!data.length}>
下载
</button>
</TooltipPopup>
);
};
图表组件
Chart基础组件
Chart
组件是所有图表类型的基础组件,封装了Chart.js库的功能,提供了统一的接口和配置管理。
样式定义
.chart
:图表容器,设置布局与高度。.tooltip
:提示框样式,采用flex布局与间距设置。
组件实现
Chart
:封装Chart.js,使用useRef
和useState
管理canvas实例与图例状态,提供创建、更新图表逻辑及图例交互功能。
const Chart: React.FC<{
config: any;
onTooltip?: (tooltip: any) => void;
}> = ({ config, onTooltip }) => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const chartRef = useRef<any>(null);
const [legend, setLegend] = useState<any[]>([]);
useEffect(() => {
if (canvasRef.current) {
chartRef.current = new ChartJS(canvasRef.current, config);
setLegend(chartRef.current.legend?.legendItems || []);
}
return () => {
if (chartRef.current) {
chartRef.current.destroy();
}
};
}, [config]);
useEffect(() => {
if (chartRef.current && onTooltip) {
chartRef.current.options.onHover = (event: any, elements: any[]) => {
if (elements.length > 0) {
const firstElement = elements[0];
const tooltipData = chartRef.current.data.datasets[firstElement.datasetIndex].data[firstElement.index];
onTooltip(tooltipData);
}
};
}
}, [onTooltip]);
return (
<div className={styles.chart}>
<canvas ref={canvasRef} />
<div className={styles.tooltip}>
{legend.map((item, index) => (
<div key={index}>{item.text}</div>
))}
</div>
</div>
);
};
BarChart
BarChart
组件用于渲染柱状图,支持单位和堆叠属性。
组件实现
BarChart
:继承ChartProps
并扩展单位、堆叠等属性,使用useMemo
创建图表配置,通过useState
管理tooltip显示。
const BarChart: React.FC<ChartProps & { unit?: string; stacked?: boolean }> = ({
data,
unit,
stacked,
}) => {
const [tooltip, setTooltip] = useState<any>(null);
const config = useMemo(() => {
return {
type: 'bar',
data,
options: {
scales: {
y: {
stacked,
},
},
},
};
}, [data, stacked]);
return (
<div className={styles.chart}>
<Chart config={config} onTooltip={setTooltip} />
{tooltip && <BarChartTooltip tooltip={tooltip} unit={unit} />}
</div>
);
};
PieChart
PieChart
组件用于渲染饼图或环形图,支持pie
或doughnut
类型。
组件实现
PieChart
:继承自Chart
,使用useState
管理tooltip,通过handleTooltip
格式化悬停数据并传递至父级组件展示。
const PieChart: React.FC<ChartProps> = ({ data }) => {
const [tooltip, setTooltip] = useState<any>(null);
const config = useMemo(() => {
return {
type: 'pie',
data,
};
}, [data]);
return (
<div className={styles.chart}>
<Chart config={config} onTooltip={setTooltip} />
{tooltip && <BarChartTooltip tooltip={tooltip} />}
</div>
);
};
BubbleChart
BubbleChart
组件用于渲染气泡图,支持bubble
类型。
组件实现
BubbleChart
:继承自通用Chart
组件并支持'bubble'
类型,使用useState
控制tooltip显示,通过handleTooltip
解析悬停数据,并用<StatusLight>
展示格式化后的信息。
const BubbleChart: React.FC<ChartProps> = ({ data }) => {
const [tooltip, setTooltip] = useState<any>(null);
const config = useMemo(() => {
return {
type: 'bubble',
data,
};
}, [data]);
return (
<div className={styles.chart}>
<Chart config={config} onTooltip={setTooltip} />
{tooltip && <BarChartTooltip tooltip={tooltip} />}
</div>
);
};
BarChartTooltip
BarChartTooltip
是柱状图的工具提示组件,用于显示悬停时的数据信息。
组件实现
BarChartTooltip
:接收tooltip
、unit
和currency
作为props,使用useLocale
获取语言环境,通过formatDate
格式化时间,并根据currency
决定数值格式。
const BarChartTooltip: React.FC<{
tooltip: any;
unit?: string;
currency?: string;
}> = ({ tooltip, unit, currency }) => {
const locale = useLocale();
const formattedTime = formatDate(tooltip.time, locale);
const formattedValue = currency
? formatCurrency(tooltip.value, currency, locale)
: `${tooltip.value} ${unit || ''}`;
return (
<div className={styles.tooltip}>
<div>{formattedTime}</div>
<div>{formattedValue}</div>
</div>
);
};
Mermaid图
布局组件关系图

输入控件关系图

图表组件关系图

表格
主要功能或组件及其描述
组件名称 | 描述 |
---|---|
Grid | 基于CSS Grid的响应式布局系统 |
MenuLayout | 侧边导航菜单布局 |
Page | 页面级布局,支持错误和加载状态管理 |
DateFilter | 日期筛选功能,支持预设时间范围或自定义日期 |
DownloadButton | 将数据转为CSV并下载 |
Chart | 图表基础组件,封装Chart.js功能 |
BarChart | 渲染柱状图,支持单位和堆叠属性 |
PieChart | 渲染饼图或环形图 |
BubbleChart | 渲染气泡图 |
BarChartTooltip | 柱状图工具提示组件 |
图表组件配置选项
配置项 | 类型 | 描述 |
---|---|---|
type | string | 图表类型(bar, pie, doughnut, bubble) |
data | object | 图表数据 |
options | object | 图表配置选项 |
unit | string | 数据单位 |
stacked | boolean | 是否堆叠显示 |
currency | string | 货币格式 |
结论
UI组件库通过模块化的CSS和React实现,提供了高度可复用和可定制的UI元素,支持响应式设计和国际化。布局组件如Grid
、MenuLayout
和Page
提供了页面结构的基础;输入控件如DateFilter
、DownloadButton
和LanguageButton
增强了用户交互;图表组件如BarChart
、PieChart
和BubbleChart
则用于数据可视化。这些组件共同构成了项目中用户界面的核心部分,确保了良好的用户体验和高度的可维护性。图表组件基于Chart.js库封装,通过统一的Chart
基础组件提供了一致的接口和配置管理,同时支持多种图表类型和交互功能。
用户模块
简介
用户模块负责处理与用户身份验证、授权和信息管理相关的功能。它包括用户登录、密码更新以及获取用户所属团队信息等核心功能。该模块通过一系列 API 接口实现,确保用户能够安全地进行身份验证和管理个人信息。
详细章节
用户登录
用户登录接口负责验证用户身份并生成认证令牌。该接口使用 zod
进行数据校验,确保用户名和密码的格式正确。通过 parseRequest
解析请求数据,并跳过默认认证。系统通过 getUserByUsername
获取用户信息,并使用 checkPassword
验证密码。如果验证成功,系统会根据 Redis 是否启用选择 saveAuth
存储或 createSecureToken
生成 JWT,并返回包含令牌和用户基础信息的 JSON 响应。
关键函数
POST
parseRequest
getUserByUsername
checkPassword
saveAuth
createSecureToken
接口信息
接口名称 | 描述 | 参数 |
---|---|---|
POST /api/auth/login | 用户登录并生成认证令牌 | username, password |
密码更新
密码更新接口允许用户更新自己的密码。该接口使用 zod
校验请求体格式,确保当前密码和新密码的格式正确。通过 parseRequest
解析请求数据,若校验失败则返回错误响应。系统从认证信息中获取用户 ID,并查询数据库验证当前密码是否正确。若验证通过,则对新密码进行哈希处理并调用 updateUser
更新密码字段,最后返回更新后的用户信息。
关键函数
POST
parseRequest
updateUser
接口信息
接口名称 | 描述 | 参数 |
---|---|---|
POST /api/me/password | 更新用户密码 | currentPassword, newPassword |
用户团队信息
用户团队信息接口用于获取指定用户所属的团队信息。该接口通过 parseRequest
解析分页参数,若失败则返回错误响应。系统提取 userId
并进行权限校验,仅允许当前用户或管理员访问。最后调用 getUserTeams(userId, query)
查询并返回结果。
关键函数
GET
parseRequest
getUserTeams
接口信息
接口名称 | 描述 | 参数 |
---|---|---|
GET /api/users/[userId]/teams | 获取用户所属团队信息 | userId |
Mermaid图
用户登录流程

密码更新流程

用户团队信息获取流程

表格
主要功能或组件及其描述
功能/组件 | 描述 |
---|---|
用户登录 | 验证用户身份并生成认证令牌 |
密码更新 | 允许用户更新自己的密码 |
用户团队信息 | 获取指定用户所属的团队信息 |
API 接口参数、类型和描述
接口 | 参数 | 类型 | 描述 |
---|---|---|---|
POST /api/auth/login | username | string | 用户名 |
password | string | 密码 | |
POST /api/me/password | currentPassword | string | 当前密码 |
newPassword | string | 新密码 | |
GET /api/users/[userId]/teams | userId | string | 用户ID |
技术实现细节
登录认证流程
用户登录接口采用多层安全验证机制。首先通过 zod
进行输入数据格式校验,确保用户名和密码符合预期格式。随后调用 parseRequest
解析请求数据并跳过默认认证流程。系统通过 getUserByUsername
从数据库获取用户信息,再使用 checkPassword
验证用户提供的密码是否正确。
在认证成功后,系统会根据 Redis 配置选择不同的令牌生成策略。如果 Redis 可用,则调用 saveAuth
将认证信息存储到 Redis 中;否则使用 createSecureToken
生成 JWT 令牌。最终返回包含认证令牌和用户基础信息的 JSON 响应。
密码安全处理
密码更新接口实施了严格的安全措施来保护用户密码信息。接口首先使用 zod
校验当前密码和新密码的格式,确保它们符合安全要求。通过 parseRequest
解析请求数据,如果校验失败则立即返回错误响应。
系统从认证信息中提取用户 ID,然后查询数据库验证用户提供的当前密码是否正确。只有在当前密码验证通过的情况下,系统才会对新密码进行哈希处理,并调用 updateUser
函数更新数据库中的密码字段。整个过程确保了密码更新的安全性和数据一致性。
权限控制机制
用户团队信息接口实现了细粒度的权限控制。接口通过 parseRequest
解析分页参数,如果解析失败则返回错误响应。系统提取请求中的 userId
参数,并进行权限校验,只允许当前用户或管理员访问该接口。
权限校验通过后,系统调用 getUserTeams(userId, query)
函数查询用户所属的团队信息。这种设计确保了用户只能访问自己或其管理范围内的用户团队信息,防止了未授权的数据访问。
数据流分析
登录数据流
- 用户提交登录请求,包含用户名和密码
- 系统使用
zod
验证输入数据格式 parseRequest
解析请求并跳过默认认证getUserByUsername
从数据库获取用户信息checkPassword
验证密码正确性- 根据 Redis 状态选择认证存储策略
- 生成认证令牌并返回用户信息
密码更新数据流
- 用户提交密码更新请求,包含当前密码和新密码
- 使用
zod
校验密码格式 parseRequest
解析请求数据- 从认证信息获取用户 ID
- 数据库验证当前密码
- 对新密码进行哈希处理
- 调用
updateUser
更新密码 - 返回更新后的用户信息
团队信息查询数据流
- 用户发起团队信息查询请求
parseRequest
解析分页参数- 提取并验证
userId
参数 - 实施权限校验(当前用户或管理员)
- 调用
getUserTeams
查询数据 - 返回团队信息结果
安全考虑
用户模块在设计和实现过程中充分考虑了安全性。所有接口都采用了输入数据验证机制,防止恶意数据注入。密码处理采用哈希算法,确保密码在存储和传输过程中的安全性。权限控制机制防止了未授权访问,确保用户只能访问其权限范围内的数据。
认证令牌的生成和存储采用了灵活的策略,既支持基于 Redis 的会话存储,也支持 JWT 令牌机制,适应不同的部署环境和安全要求。
结论/总结
用户模块通过一系列 API 接口实现了用户身份验证、密码更新和团队信息获取等功能。这些功能确保了用户能够安全地进行身份验证和管理个人信息,是项目中不可或缺的一部分。通过详细的流程图和表格,开发人员可以更好地理解模块的架构和实现细节。
测试与部署模块
简介
测试与部署模块是本项目中负责验证系统功能、确保数据一致性和服务可用性的关键部分。它涵盖了从用户界面到后端 API 的端到端测试,以及数据库迁移和心跳检测等基础设施层面的保障机制。
模块通过 Cypress 编写的 E2E 和 API 测试脚本,验证用户、团队、网站管理等功能的正确性。同时,通过 数据库迁移 机制和 心跳检测接口 确保系统的稳定性和数据完整性。
详细章节
Cypress 测试套件
Cypress 测试套件用于验证前端用户交互和后端 API 接口的正确性。测试脚本覆盖了用户、团队、网站的增删改查操作,以及登录流程的验证。
用户管理测试
api-user.cy.ts
:验证用户创建、获取、更新、删除等 API 接口。user.cy.ts
:模拟用户添加、编辑、删除操作,并通过登录验证更改是否生效。
团队管理测试
api-team.cy.ts
:覆盖团队的创建、获取、更新、删除及用户管理操作。
网站管理测试
api-website.cy.ts
:测试网站的创建、获取、更新、重置与删除。website.cy.ts
:模拟网站添加、编辑、删除流程,并验证表单提交结果。
登录流程测试
login.cy.ts
:验证登录与退出功能,以及错误处理逻辑。

数据库迁移
数据库迁移机制通过 migration_lock.toml
文件确保在多环境或多人协作下迁移操作的原子性和一致性。该文件由迁移工具自动生成并维护,防止迁移冲突。
心跳检测接口
心跳检测接口用于监控服务的可用性。src/app/api/heartbeat/route.ts
文件中定义了一个异步 GET
函数,处理 HTTP GET 请求,返回 { ok: true }
表示服务正常。
// src/app/api/heartbeat/route.ts
export async function GET() {
return Response.json({ ok: true });
}
数据模型
数据库结构通过 schema.prisma
文件定义,包含用户、会话、网站、事件、团队、报告等模型,支持用户行为分析、流量监控、团队协作及数据报告生成。

表格
主要功能或组件及其描述
功能/组件 | 描述 |
---|---|
Cypress 测试套件 | 用于验证前端用户交互和后端 API 接口的正确性 |
数据库迁移 | 通过 migration_lock.toml 文件确保迁移操作的原子性和一致性 |
心跳检测接口 | 用于监控服务的可用性 |
数据模型 | 通过 schema.prisma 文件定义数据库结构 |
API 接口参数、类型和描述
接口名称 | 描述 | 参数 |
---|---|---|
GET /api/heartbeat | 心跳检测接口 | 无 |
结论/总结
测试与部署模块通过全面的测试套件、数据库迁移机制和心跳检测接口,确保了系统的功能正确性、数据一致性和服务可用性。它是项目稳定运行的重要保障。
报告模块
简介
报告模块是项目中用于展示和分析用户行为数据的核心功能模块,主要包括目标报告(Goals)、用户留存报告(Retention)和漏斗分析报告(Funnel)。每个报告类型通过独立的页面和组件结构实现,提供参数配置、数据可视化和交互功能。模块通过 ReportContext
管理状态,结合国际化支持(useMessages
)和模块化 CSS 样式,构建统一且可扩展的报告界面。
目标报告(Goals)
功能概述
目标报告模块用于跟踪和展示用户完成特定目标(如访问 URL、触发事件)的进度。通过配置目标参数、添加或编辑目标,并以卡片式图表展示完成情况。
核心组件
- GoalsReportPage:页面入口组件,渲染
GoalsReport
。 - GoalsReport:主组件,组合
<ReportHeader>
、<GoalsParameters>
和<GoalsChart>
。 - GoalsParameters:目标参数配置组件,支持添加、编辑和删除目标。
- GoalsChart:目标进度可视化组件,展示目标完成百分比和进度条。
- GoalsAddForm:添加或更新目标的表单组件。
样式文件
GoalsAddForm.module.css
:定义表单组件的布局与尺寸。GoalsChart.module.css
:定义图表界面的样式类。GoalsParameters.module.css
:增强参数界面的可读性和视觉区分度。GoalsReport.module.css
:样式化过滤器区域。
Mermaid 图

表格:主要功能或组件
组件/文件 | 描述 |
---|---|
GoalsReportPage | 页面入口组件 |
GoalsReport | 主组件,组合其他子组件 |
GoalsParameters | 目标参数配置组件 |
GoalsChart | 目标进度可视化组件 |
GoalsAddForm | 添加或更新目标的表单组件 |
用户留存报告(Retention)
功能概述
用户留存报告模块用于分析用户在特定时间段内的留存情况。通过配置日期范围和其他参数,以表格形式展示不同天数的留存率数据。
核心组件
- RetentionReportPage:页面入口组件,渲染
RetentionReport
。 - RetentionReport:主组件,组合
<ReportHeader>
、<ReportMenu>
和<ReportBody>
。 - RetentionParameters:参数配置组件,支持日期选择和表单提交。
- RetentionTable:留存数据展示组件,以表格形式渲染数据。
样式文件
RetentionReport.module.css
:样式化过滤器区域。RetentionTable.module.css
:定义表格样式结构。
Mermaid 图

表格:主要功能或组件
组件/文件 | 描述 |
---|---|
RetentionReportPage | 页面入口组件 |
RetentionReport | 主组件,组合其他子组件 |
RetentionParameters | 参数配置组件 |
RetentionTable | 留存数据展示组件 |
漏斗分析报告(Funnel)
功能概述
漏斗分析报告模块用于跟踪用户在多步骤流程中的转化情况。通过配置漏斗步骤、添加或编辑步骤,并以漏斗图形式展示每一步的转化率和流失情况。
核心组件
- FunnelReportPage:页面入口组件,渲染
FunnelReport
。 - FunnelReport:主组件,组合
<ReportHeader>
、<ReportMenu>
和<ReportBody>
。 - FunnelParameters:参数配置组件,支持添加、编辑和删除漏斗步骤。
- FunnelChart:漏斗数据可视化组件,展示每一步的转化率和进度条。
- FunnelStepAddForm:添加或更新漏斗步骤的表单组件。
样式文件
FunnelChart.module.css
:定义漏斗图组件样式。FunnelParameters.module.css
:定义参数项样式。FunnelReport.module.css
:样式化过滤器区域。FunnelStepAddForm.module.css
:定义表单组件的布局与尺寸。
Mermaid 图

表格:主要功能或组件
组件/文件 | 描述 |
---|---|
FunnelReportPage | 页面入口组件 |
FunnelReport | 主组件,组合其他子组件 |
FunnelParameters | 参数配置组件 |
FunnelChart | 漏斗数据可视化组件 |
FunnelStepAddForm | 添加或更新漏斗步骤的表单组件 |
状态管理与数据流
ReportContext 的作用
所有报告模块均依赖 ReportContext
来获取和管理状态信息。该上下文提供统一的数据源和状态更新方法,确保组件间数据同步和交互一致性。
数据获取与处理流程
- 目标报告:
GoalsParameters
通过ReportContext
获取报告状态- 用户添加或编辑目标后,调用回调提交数据
GoalsChart
从上下文中获取数据并计算完成百分比
- 用户留存报告:
RetentionParameters
通过ReportContext
获取状态信息- 用户配置日期范围后,触发查询执行
RetentionTable
从上下文中获取数据并渲染表格
- 漏斗分析报告:
FunnelParameters
依赖ReportContext
和useMessages
- 用户添加、编辑或删除漏斗步骤后,更新上下文状态
FunnelChart
从上下文中获取数据并动态渲染步骤卡片
表单提交与参数更新
- GoalsAddForm:维护输入值状态,调用回调提交数据
- RetentionParameters:包含
handleSubmit
和handleDateChange
核心函数 - FunnelStepAddForm:支持回车键或按钮提交,确保输入有效性后触发回调
总结
报告模块通过目标报告、用户留存报告和漏斗分析报告三个子模块,全面覆盖用户行为数据的分析需求。每个子模块均采用组件化设计,结合模块化 CSS 和国际化支持,确保界面统一且功能完整。通过 ReportContext
管理状态,模块间数据流清晰,便于维护和扩展。各组件通过上下文共享状态和方法,实现了高效的数据交互和视图更新。表单提交和参数更新机制保证了用户配置的实时生效,提升了用户体验。整个模块设计遵循 Next.js 页面规范,具有良好的可维护性和可扩展性。
工具模块
工具模块是项目中多个功能模块的基础支撑,提供通用的辅助函数、数据处理逻辑、认证机制、数据库交互、消息队列集成等。这些工具模块旨在提升代码复用性、降低耦合度,并为上层业务逻辑提供统一的接口和标准化的处理流程。
认证与权限控制
功能概述
认证与权限控制模块(auth.ts
)负责系统的身份验证和权限管理。它使用 bcrypt 进行密码加密验证,JWT 令牌解析,Redis 缓存存储,并提供多个以 can...
命名的异步权限判断函数,支持基于角色的权限控制(RBAC)。
核心函数
checkAuth()
: 验证请求中的 token 并返回用户信息。saveAuth()
: 存储认证信息并生成 Token。can...()
: 异步权限判断函数。
数据流

表格:认证与权限控制函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
checkAuth() | 验证请求中的 token 并返回用户信息 | token | 用户信息 |
saveAuth() | 存储认证信息并生成 Token | userInfo | Token |
can...() | 异步权限判断函数 | userId , permission | boolean |
数据处理与格式化
功能概述
数据处理与格式化模块(data.ts
, format.ts
, charts.ts
)提供嵌套 JSON 展平、数据类型识别、时间、数字、货币格式化以及图表标签优化等功能。
核心函数
flattenJSON()
: 递归展平对象。getDataType()
: 判断值的数据类型。formatNumber()
: 处理数值显示。renderNumberLabels()
: 格式化大数为缩写形式。
数据流

表格:数据处理与格式化函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
flattenJSON() | 递归展平对象 | obj | 展平后的对象 |
getDataType() | 判断值的数据类型 | value | 数据类型 |
formatNumber() | 处理数值显示 | n | 格式化后的数值 |
renderNumberLabels() | 格式化大数为缩写形式 | value | 缩写形式的数值 |
数据库交互
功能概述
数据库交互模块(db.ts
, prisma.ts
, clickhouse.ts
)封装了数据库连接、查询构建、分页等功能,支持多种数据库系统(如 Prisma ORM、ClickHouse)。
核心函数
getDatabaseType()
: 解析环境变量确定当前数据库。runQuery()
: 根据类型选择对应查询逻辑。getClient()
: 创建并缓存客户端实例。pagedQuery()
: 实现分页查询。
数据流

表格:数据库交互函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getDatabaseType() | 解析环境变量确定当前数据库 | 无 | 数据库类型 |
runQuery() | 根据类型选择对应查询逻辑 | query | 查询结果 |
getClient() | 创建并缓存客户端实例 | 无 | 客户端实例 |
pagedQuery() | 实现分页查询 | query , page , size | 分页结果 |
消息队列集成
功能概述
消息队列集成模块(kafka.ts
)支持 Kafka 消息队列系统的集成,提供消息发送和连接管理功能。
核心函数
getClient()
: 初始化 Kafka 客户端。getProducer()
: 创建生产者实例。sendMessage()
: 发送 JSON 格式消息。
数据流

表格:消息队列集成函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getClient() | 初始化 Kafka 客户端 | 无 | 客户端实例 |
getProducer() | 创建生产者实例 | 无 | 生产者实例 |
sendMessage() | 发送 JSON 格式消息 | topic , message | 无 |
HTTP 请求处理
功能概述
HTTP 请求处理模块(fetch.ts
, request.ts
, response.ts
)封装了通用 HTTP 请求模块,支持 GET、POST、PUT、DELETE 方法,并提供请求体解析、数据验证、身份认证和响应构建功能。
核心函数
request()
: 核心请求函数。getJsonBody()
: 解析请求体。parseRequest()
: 验证数据。ok()
: 构建成功响应。
数据流

表格:HTTP 请求处理函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
request() | 核心请求函数 | method , url , options | 响应 |
getJsonBody() | 解析请求体 | request | JSON 对象 |
parseRequest() | 验证数据 | request | 验证结果 |
ok() | 构建成功响应 | data | 成功响应 |
客户端认证令牌管理
功能概述
客户端认证令牌管理模块(client.ts
)提供客户端认证令牌的读取、设置与删除操作,为客户端应用提供统一的身份验证状态管理接口。
核心函数
getClientAuthToken()
: 获取本地存储中的认证令牌。setClientAuthToken(token)
: 设置认证令牌。removeClientAuthToken()
: 删除认证令牌。
数据流

表格:客户端认证令牌管理函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getClientAuthToken() | 获取本地存储中的认证令牌 | 无 | 令牌 |
setClientAuthToken() | 设置认证令牌 | token | 无 |
removeClientAuthToken() | 删除认证令牌 | 无 | 无 |
颜色处理工具
功能概述
颜色处理工具模块(colors.ts
)提供颜色处理工具函数,支持格式转换与颜色生成,适用于前端 UI 的配色需求。
核心函数
hex2RGB()
: 将十六进制颜色转换为RGB。rgb2Hex()
: 将RGB颜色转换为十六进制。getPastel()
: 生成柔和色调。getColor()
: 使用 MD5 算法根据种子生成唯一颜色。
数据流

表格:颜色处理工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
hex2RGB() | 将十六进制颜色转换为RGB | hex | RGB对象 |
rgb2Hex() | 将RGB颜色转换为十六进制 | r , g , b | 十六进制颜色 |
getPastel() | 生成柔和色调 | 无 | 颜色值 |
getColor() | 使用 MD5 算法根据种子生成唯一颜色 | seed | 颜色值 |
全局常量与配置管理
功能概述
全局常量与配置管理模块(constants.ts
)集中管理项目中使用的全局常量与配置,减少硬编码,提高代码维护性。
核心功能
- 定义版本、认证、国际化、主题等系统级参数。
- 包含事件类型、列字段映射、权限设置等结构化常量。
- 提供正则表达式、设备分类、网站域名组等辅助数据。
数据流

表格:全局常量与配置
常量名 | 描述 | 类型 | 默认值 |
---|---|---|---|
VERSION | 系统版本 | string | "1.0.0" |
AUTH_COOKIE_NAME | 认证Cookie名称 | string | "auth-token" |
EVENT_TYPES | 事件类型映射 | object | { pageview: "pageview", event: "event" } |
PERMISSIONS | 权限设置 | object | 权限配置对象 |
加密与安全工具
功能概述
加密与安全工具模块(crypto.ts
)提供加密、解密、哈希计算与 UUID 生成功能,确保数据安全性与唯一标识生成。
核心函数
encrypt()
: 使用 AES-256-GCM 加密算法加密数据。decrypt()
: 使用 AES-256-GCM 解密算法解密数据。hash()
: 使用 SHA-512 计算哈希值。generateUUID()
: 生成 UUID v4/v5。
数据流

表格:加密与安全工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
encrypt() | 使用 AES-256-GCM 加密算法加密数据 | data , key | 加密后的数据 |
decrypt() | 使用 AES-256-GCM 解密算法解密数据 | encryptedData , key | 解密后的数据 |
hash() | 使用 SHA-512 计算哈希值 | data | 哈希值 |
generateUUID() | 生成 UUID v4/v5 | version , namespace , name | UUID |
日期处理工具
功能概述
日期处理工具模块(date.ts
)封装日期处理逻辑,支持范围解析、偏移计算与格式化,统一项目中的日期处理逻辑。
核心函数
parseDateRange()
: 解析时间表达式为日期范围。getDateArray()
: 生成指定单位的时间序列。formatDate()
: 支持多语言格式化输出。
数据流

表格:日期处理工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
parseDateRange() | 解析时间表达式为日期范围 | expression | 日期范围对象 |
getDateArray() | 生成指定单位的时间序列 | start , end , unit | 时间序列数组 |
formatDate() | 支持多语言格式化输出 | date , locale | 格式化后的日期字符串 |
客户端信息检测
功能概述
客户端信息检测模块(detect.ts
)负责从 HTTP 请求中提取客户端信息,包括 IP、地理位置、设备类型、操作系统和浏览器等,用于访问控制、日志记录等场景。
核心函数
getIpAddress(headers)
: 提取客户端 IP。getDevice(screen, os)
: 判断设备类型。getLocation(ip, headers, hasPayloadIP)
: 获取地理位置。getClientInfo(request, payload)
: 整合客户端信息。hasBlockedIp(clientIp)
: 检查 IP 是否在黑名单。
数据流

表格:客户端信息检测函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getIpAddress() | 提取客户端 IP | headers | IP地址 |
getDevice() | 判断设备类型 | screen , os | 设备类型 |
getLocation() | 获取地理位置 | ip , headers , hasPayloadIP | 地理位置信息 |
getClientInfo() | 整合客户端信息 | request , payload | 客户端信息对象 |
hasBlockedIp() | 检查 IP 是否在黑名单 | clientIp | boolean |
数据过滤工具
功能概述
数据过滤工具模块(filters.ts
)包含多个数据过滤函数,用于统计分析场景,如流量来源、URL 路径等数据聚合。
核心函数
urlFilter(data)
: 按字段分组并累加值。refFilter(data)
: 提取域名并保留原始 URL。emptyFilter(data)
: 过滤空值。percentFilter(data)
: 计算占比。paramFilter(data)
: 解析 URL 参数并分组。
数据流

表格:数据过滤工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
urlFilter() | 按字段分组并累加值 | data | 过滤后的数据 |
refFilter() | 提取域名并保留原始 URL | data | 过滤后的数据 |
emptyFilter() | 过滤空值 | data | 过滤后的数据 |
percentFilter() | 计算占比 | data | 包含占比的数据 |
paramFilter() | 解析 URL 参数并分组 | data | 过滤后的数据 |
JWT令牌处理
功能概述
JWT令牌处理模块(jwt.ts
)实现 JWT 的创建、解析及加密操作,提供标准 JWT 操作及增强安全机制。
核心函数
createToken(payload, secret)
: 生成 JWT。parseToken(token, secret)
: 解析 JWT。createSecureToken()
: 加密 JWT。parseSecureToken()
: 解密 JWT。parseAuthToken(req, secret)
: 从请求头提取并解析安全令牌。
数据流

表格:JWT令牌处理函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
createToken() | 生成 JWT | payload , secret | JWT令牌 |
parseToken() | 解析 JWT | token , secret | 解析后的载荷 |
createSecureToken() | 加密 JWT | payload , secret | 加密后的JWT |
parseSecureToken() | 解密 JWT | token , secret | 解密后的载荷 |
parseAuthToken() | 从请求头提取并解析安全令牌 | req , secret | 解析后的载荷 |
多语言支持
功能概述
多语言支持模块(lang.ts
)管理多语言配置与工具函数,导入 date-fns
提供的语言本地化对象,构建 languages
对象,用于国际化中的日期格式与布局方向调整。
核心函数
getDateLocale(locale)
: 返回对应日期本地化对象。getTextDirection(locale)
: 返回文本方向。
数据流

表格:多语言支持函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getDateLocale() | 返回对应日期本地化对象 | locale | 本地化对象 |
getTextDirection() | 返回文本方向 | locale | "ltr" 或 "rtl" |
数据加载与缓存
功能概述
数据加载与缓存模块(load.ts
)提供异步加载网站和会话信息的函数,优先使用 Redis 缓存提高性能,结合缓存与数据库查询,确保返回有效数据。
核心函数
fetchWebsite()
: 加载网站信息。fetchSession()
: 加载会话信息。
数据流

表格:数据加载与缓存函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
fetchWebsite() | 加载网站信息 | websiteId | 网站信息对象 |
fetchSession() | 加载会话信息 | sessionId | 会话信息对象 |
查询参数处理
功能概述
查询参数处理模块(params.ts
)处理查询参数解析与转换,将前端传入的 filters 解析为统一结构数组,提升接口兼容性与灵活性。
核心函数
parseParameterValue(param)
: 提取操作符与值。filtersToArray(filters, options)
: 转换为数组格式。
数据流

表格:查询参数处理函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
parseParameterValue() | 提取操作符与值 | param | 解析结果对象 |
filtersToArray() | 转换为数组格式 | filters , options | 数组格式的过滤器 |
Redis缓存管理
功能概述
Redis缓存管理模块(redis.ts
)用于初始化并导出 Redis 客户端实例,通过检查 REDIS_URL
环境变量决定是否启用 Redis,定义 getClient
创建客户端,并在非生产环境挂载到全局对象。
核心功能
- 初始化Redis客户端实例
- 环境变量检查与配置
- 全局实例管理
数据流

表格:Redis缓存管理配置
配置项 | 描述 | 类型 | 默认值 |
---|---|---|---|
REDIS_URL | Redis连接URL | string | 无 |
client | Redis客户端实例 | RedisClient | 实例对象 |
enabled | 是否启用Redis | boolean | 根据环境变量确定 |
请求处理工具
功能概述
请求处理工具模块(request.ts
)提供 HTTP 请求处理工具函数,包括解析请求体、验证数据、身份认证和提取查询参数,支持 Zod 校验与错误回调,标准化后端接口的请求处理流程。
核心函数
getJsonBody()
: 解析请求体。parseRequest()
: 验证数据。getRequestDateRange()
: 提取日期范围。getRequestFilters()
: 提取查询过滤器。
数据流

表格:请求处理工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getJsonBody() | 解析请求体 | request | JSON对象 |
parseRequest() | 验证数据 | request , schema | 验证结果 |
getRequestDateRange() | 提取日期范围 | request | 日期范围对象 |
getRequestFilters() | 提取查询过滤器 | request | 过滤器对象 |
响应处理工具
功能概述
响应处理工具模块(response.ts
)提供构建 HTTP 响应的辅助函数,如 ok
, badRequest
, unauthorized
等,统一 API 响应格式与错误处理,所有错误响应使用 serialize-error
序列化错误信息,确保 JSON 安全传输。
核心函数
ok()
: 构建成功响应。badRequest()
: 构建错误请求响应。unauthorized()
: 构建未授权响应。notFound()
: 构建未找到响应。serverError()
: 构建服务器错误响应。
数据流

表格:响应处理工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
ok() | 构建成功响应 | data | 成功响应对象 |
badRequest() | 构建错误请求响应 | error | 错误响应对象 |
unauthorized() | 构建未授权响应 | error | 错误响应对象 |
notFound() | 构建未找到响应 | error | 错误响应对象 |
serverError() | 构建服务器错误响应 | error | 错误响应对象 |
数据校验模式
功能概述
数据校验模式模块(schema.ts
)定义多个 Zod schema 用于数据校验,涵盖过滤条件、分页参数、时区、单位、角色、URL、报告类型等,用于前后端统一输入格式校验,增强接口健壮性和开发效率。
核心模式
filterSchema
: 过滤条件校验模式。paginationSchema
: 分页参数校验模式。timezoneSchema
: 时区校验模式。roleSchema
: 角色校验模式。urlSchema
: URL校验模式。
数据流

表格:数据校验模式
模式名 | 描述 | 校验字段 | 类型 |
---|---|---|---|
filterSchema | 过滤条件校验模式 | column , operator , value | 对象 |
paginationSchema | 分页参数校验模式 | page , size | 对象 |
timezoneSchema | 时区校验模式 | timezone | 字符串 |
roleSchema | 角色校验模式 | role | 字符串枚举 |
urlSchema | URL校验模式 | url | 字符串 |
本地存储工具
功能概述
本地存储工具模块(storage.ts
)封装浏览器本地存储操作,提供 setItem
, getItem
, removeItem
函数,支持 localStorage
和 sessionStorage
,仅在客户端运行,避免 SSR 错误,简化存储交互逻辑。
核心函数
setItem()
: 设置存储项。getItem()
: 获取存储项。removeItem()
: 移除存储项。
数据流

表格:本地存储工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
setItem() | 设置存储项 | key , value , storageType | 无 |
getItem() | 获取存储项 | key , storageType | 存储值 |
removeItem() | 移除存储项 | key , storageType | 无 |
URL处理工具
功能概述
URL处理工具模块(url.ts
)提供 URL 操作工具函数,包括 getQueryString
, buildUrl
, safeDecodeURI
, safeDecodeURIComponent
,用于构建、拼接和安全解码 URL,增强 URL 处理的安全性与灵活性。
核心函数
getQueryString()
: 构建查询字符串。buildUrl()
: 构建完整URL。safeDecodeURI()
: 安全解码URI。safeDecodeURIComponent()
: 安全解码URI组件。
数据流

表格:URL处理工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
getQueryString() | 构建查询字符串 | params | 查询字符串 |
buildUrl() | 构建完整URL | baseUrl , path , params | 完整URL |
safeDecodeURI() | 安全解码URI | uri | 解码后的URI |
safeDecodeURIComponent() | 安全解码URI组件 | uriComponent | 解码后的组件 |
通用工具函数
功能概述
通用工具函数模块(utils.ts
)提供了多个通用工具函数,包括方法扩展、异步延时、数组操作等,这些函数简洁、泛型友好,适合项目中复用。
核心函数
hook()
: 扩展对象方法,支持前置回调。sleep()
: 实现指定毫秒数的异步延时。shuffleArray()
: 使用 Fisher-Yates 算法打乱数组。chunkArray()
: 按大小分块数组。ensureArray()
: 确保输入为数组。
数据流

表格:通用工具函数
函数名 | 描述 | 参数 | 返回值 |
---|---|---|---|
hook() | 扩展对象方法,支持前置回调 | target , methodName , callback | 无 |
sleep() | 实现指定毫秒数的异步延时 | ms | Promise |
shuffleArray() | 使用 Fisher-Yates 算法打乱数组 | array | 打乱后的数组 |
chunkArray() | 按大小分块数组 | array , size | 分块后的数组 |
ensureArray() | 确保输入为数组 | input | 数组 |
结论
工具模块通过提供认证与权限控制、数据处理与格式化、数据库交互、消息队列集成、HTTP请求处理、客户端认证管理、颜色处理、全局常量配置、加密安全、日期处理、客户端信息检测、数据过滤、JWT令牌处理、多语言支持、数据加载缓存、查询参数处理、Redis缓存管理、请求响应处理、数据校验模式、本地存储操作、URL处理以及通用工具函数等功能,为项目中的其他模块提供了坚实的基础。这些工具模块不仅提升了代码的复用性和可维护性,还确保了系统的安全性和稳定性,是整个项目架构中不可或缺的重要组成部分。
应用主界面
应用主界面是 Umami 应用的核心用户交互层,负责组织和展示所有主要功能模块。它通过模块化的布局结构,将导航、内容区域和全局状态管理有机结合,为用户提供一致且高效的使用体验。主界面依赖于 Next.js 的布局系统和 React Context 进行状态传递,并通过 Providers
组件集成国际化、数据查询和错误处理等核心功能。
整体架构
应用主界面由多个层级的布局组件构成,从根布局到主布局,再到具体页面,形成清晰的结构层次。
根布局 (src/app/layout.tsx
)
根布局定义了整个应用的基础 HTML 结构,包括 <html>
、<head>
和 <body>
标签。它引入了全局样式、字体和元数据,并通过 Providers
组件包裹所有子内容,实现全局状态管理和功能配置。
import './globals.css';
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import { Providers } from './Providers';
import { getConfig } from '@/lib/config';
const inter = Inter({ subsets: ['latin'] });
export async function generateMetadata(): Promise<Metadata> {
const config = await getConfig();
const { basePath, title, description, favicon, themeColor } = config;
return {
title: title,
description: description,
icons: {
icon: favicon,
},
themeColor: themeColor,
metadataBase: new URL(basePath),
};
}
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const config = await getConfig();
if (config?.disableUI) {
return <html lang="en" className={inter.className}></html>;
}
return (
<html lang="en" className={inter.className}>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
主布局 (src/app/(main)/layout.tsx
)
主布局是应用核心功能的容器,使用 CSS Grid 布局将页面划分为导航栏和内容区域。它引入了 NavBar
组件作为顶部导航,并通过 <Page>{children}</Page>
渲染子页面内容。主布局还设置了页面标题模板,确保所有子页面标题格式统一。
import { Page } from 'react-basics';
import { NavBar } from './NavBar';
import styles from './layout.module.css';
export const metadata = {
title: {
template: '%s | Umami',
default: 'Umami',
},
};
export default function MainLayout({ children }: { children: React.ReactNode }) {
return (
<div className={styles.layout}>
<div className={styles.nav}>
<NavBar />
</div>
<div className={styles.body}>
<Page>{children}</Page>
</div>
</div>
);
}
主应用组件 (src/app/(main)/App.tsx
)
App
组件是主界面的入口,负责协调用户登录状态、应用配置和路由路径。它通过 useLogin
、useConfig
和 usePathname
获取必要状态,并在加载时显示 <Loading />
组件。登录失败时会重定向用户,用户或配置未就绪时返回空内容,最终渲染子组件和通知。
'use client';
import { Loading } from 'react-basics';
import Script from 'next/script';
import { usePathname } from 'next/navigation';
import { useLogin, useConfig } from '@/components/hooks';
import UpdateNotice from './UpdateNotice';
export function App({ children }) {
const { user, isLoading, error } = useLogin();
const config = useConfig();
const pathname = usePathname();
if (isLoading) {
return <Loading />;
}
if (error) {
window.location.href = `${process.env.basePath || ''}/login`;
}
if (!user || !config) {
return null;
}
return (
<>
{children}
<UpdateNotice user={user} config={config} />
{process.env.NODE_ENV === 'production' && !pathname.includes('/share/') && (
<Script src={`${process.env.basePath || ''}/telemetry.js`} />
)}
</>
);
}
export default App;

导航栏 (src/app/(main)/NavBar.tsx
)
导航栏是应用主界面的重要组成部分,提供全局导航和用户操作入口。它集成了以下功能:
- Logo: 应用标识,通常位于左侧。
- 导航链接: 包括仪表盘、网站、报告等主要功能模块的链接。
- 主题切换: 允许用户在浅色和深色主题之间切换。
- 语言选择: 提供多语言支持,允许用户选择界面语言。
- 用户资料: 显示当前用户信息,并提供退出登录等操作。
- 团队切换: 允许用户在不同团队之间切换。
- 移动端支持: 通过汉堡菜单适配移动设备。
导航栏使用 CSS Grid 布局,分为 .logo
、.links
和 .actions
三个区域,并通过媒体查询在移动端隐藏部分模块,显示 .mobile
模块。
'use client';
import { useEffect } from 'react';
import { Icon, Text } from 'react-basics';
import Link from 'next/link';
import classNames from 'classnames';
import HamburgerButton from '@/components/common/HamburgerButton';
import ThemeButton from '@/components/input/ThemeButton';
import LanguageButton from '@/components/input/LanguageButton';
import ProfileButton from '@/components/input/ProfileButton';
import TeamsButton from '@/components/input/TeamsButton';
import Icons from '@/components/icons';
import { useMessages, useNavigation, useTeamUrl } from '@/components/hooks';
import { getItem, setItem } from '@/lib/storage';
import styles from './NavBar.module.css';
export function NavBar() {
const { formatMessage, labels } = useMessages();
const { pathname, router } = useNavigation();
const { teamId, renderTeamUrl } = useTeamUrl();
const cloudMode = !!process.env.cloudMode;
const links = [
{ label: formatMessage(labels.dashboard), url: renderTeamUrl('/dashboard') },
{ label: formatMessage(labels.websites), url: renderTeamUrl('/websites') },
{ label: formatMessage(labels.reports), url: renderTeamUrl('/reports') },
{ label: formatMessage(labels.settings), url: renderTeamUrl('/settings') },
].filter(n => n);
const menuItems = [
{
label: formatMessage(labels.dashboard),
url: renderTeamUrl('/dashboard'),
},
!cloudMode && {
label: formatMessage(labels.settings),
url: renderTeamUrl('/settings'),
children: [
...(teamId
? [
{
label: formatMessage(labels.team),
url: renderTeamUrl('/settings/team'),
},
]
: []),
{
label: formatMessage(labels.websites),
url: renderTeamUrl('/settings/websites'),
},
...(!teamId
? [
{
label: formatMessage(labels.teams),
url: renderTeamUrl('/settings/teams'),
},
{
label: formatMessage(labels.users),
url: '/settings/users',
},
]
: [
{
label: formatMessage(labels.members),
url: renderTeamUrl('/settings/members'),
},
]),
],
},
{
label: formatMessage(labels.profile),
url: '/profile',
},
!cloudMode && { label: formatMessage(labels.logout), url: '/logout' },
].filter(n => n);
const handleTeamChange = (teamId: string) => {
const url = teamId ? `/teams/${teamId}` : '/';
if (!cloudMode) {
setItem('umami.team', { id: teamId });
}
router.push(cloudMode ? `${process.env.cloudUrl}${url}` : url);
};
useEffect(() => {
if (!cloudMode) {
const teamIdLocal = getItem('umami.team')?.id;
if (teamIdLocal && teamIdLocal !== teamId) {
router.push(
pathname !== '/' && pathname !== '/dashboard' ? '/' : `/teams/${teamIdLocal}/dashboard`,
);
}
}
}, [cloudMode]);
return (
<div className={styles.navbar}>
<div className={styles.logo}>
<Icon size="lg">
<Icons.Logo />
</Icon>
<Text>umami</Text>
</div>
<div className={styles.links}>
{links.map(({ url, label }) => {
return (
<Link
key={url}
href={url}
className={classNames({ [styles.selected]: pathname.startsWith(url) })}
prefetch={url !== '/settings'}
>
<Text>{label}</Text>
</Link>
);
})}
</div>
<div className={styles.actions}>
<TeamsButton onChange={handleTeamChange} />
<ThemeButton />
<LanguageButton />
<ProfileButton />
</div>
<div className={styles.mobile}>
<TeamsButton onChange={handleTeamChange} showText={false} />
<HamburgerButton menuItems={menuItems} />
</div>
</div>
);
}
export default NavBar;

全局状态管理 (src/app/Providers.tsx
)
Providers
组件集中管理应用的全局状态和功能配置,包括:
- QueryClientProvider: 配置 react-query,用于数据获取和状态管理。
- IntlProvider: 提供国际化支持,管理多语言资源。
- ReactBasicsProvider: 配置基础 UI 工具。
- ErrorBoundary: 捕获和处理组件树中的 JavaScript 错误。
通过 Providers
组件,应用主界面能够统一管理全局状态,确保各功能模块之间的数据一致性和功能协调性。
'use client';
import { IntlProvider } from 'react-intl';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactBasicsProvider } from 'react-basics';
import ErrorBoundary from '@/components/common/ErrorBoundary';
import { useLocale } from '@/components/hooks';
import 'chartjs-adapter-date-fns';
import { useEffect } from 'react';
const client = new QueryClient({
defaultOptions: {
queries: {
retry: false,
refetchOnWindowFocus: false,
},
},
});
function MessagesProvider({ children }) {
const { locale, messages, dir } = useLocale();
useEffect(() => {
document.documentElement.setAttribute('dir', dir);
document.documentElement.setAttribute('lang', locale);
}, [locale, dir]);
return (
<IntlProvider locale={locale} messages={messages[locale]} onError={() => null}>
{children}
</IntlProvider>
);
}
export function Providers({ children }) {
return (
<MessagesProvider>
<QueryClientProvider client={client}>
<ReactBasicsProvider>
<ErrorBoundary>{children}</ErrorBoundary>
</ReactBasicsProvider>
</QueryClientProvider>
</MessagesProvider>
);
}
export default Providers;
样式和布局
应用主界面的样式和布局通过 CSS Modules 进行管理,确保样式隔离和可维护性。
主布局样式 (src/app/(main)/layout.module.css
)
主布局使用 CSS Grid 定义了页面的整体结构:
.layout
: 使用grid-template-rows: max-content 1fr
,将页面划分为固定高度的导航栏和可滚动的内容区域。.nav
: 固定高度为 60px,用于放置导航栏。.body
: 可滚动的内容区域。
.layout {
display: grid;
grid-template-rows: max-content 1fr;
grid-template-columns: 1fr;
overflow: hidden;
}
.nav {
height: 60px;
width: 100vw;
grid-column: 1;
grid-row: 1 / 2;
}
.body {
grid-column: 1;
grid-row: 2 / 3;
min-height: 0;
height: calc(100vh - 60px);
height: calc(100dvh - 60px);
overflow-y: auto;
}
导航栏样式 (src/app/(main)/NavBar.module.css
)
导航栏使用 CSS Grid 布局,分为三个主要区域:
.navbar
: 导航栏容器。.logo
: Logo 区域。.links
: 导航链接区域。.actions
: 操作按钮区域。.mobile
: 移动端菜单区域。
.navbar {
display: grid;
grid-template-columns: max-content 1fr max-content;
align-items: center;
height: 100%;
padding: 0 20px;
border-bottom: 1px solid var(--base300);
background: var(--base50);
}
.logo {
display: flex;
align-items: center;
gap: 10px;
font-weight: 700;
font-size: 20px;
color: var(--primary400);
}
.links {
display: flex;
gap: 30px;
justify-content: center;
}
.links a {
display: flex;
align-items: center;
height: 100%;
padding: 0 10px;
color: var(--base700);
text-decoration: none;
border-bottom: 2px solid transparent;
transition: border-color 0.2s ease;
}
.links a:hover,
.links a.selected {
border-bottom: 2px solid var(--primary400);
}
.actions {
display: flex;
align-items: center;
gap: 10px;
}
.mobile {
display: none;
}
@media (max-width: 768px) {
.navbar {
grid-template-columns: max-content 1fr max-content;
}
.links {
display: none;
}
.actions {
display: none;
}
.mobile {
display: flex;
align-items: center;
gap: 10px;
}
}
主要功能和组件
组件/功能 | 描述 |
---|---|
layout.tsx | 根布局,定义基础 HTML 结构和全局样式。 |
(main)/layout.tsx | 主布局,使用 CSS Grid 划分导航栏和内容区域。 |
App.tsx | 主应用组件,协调登录状态、配置和路由。 |
NavBar.tsx | 导航栏组件,提供全局导航和用户操作入口。 |
Providers.tsx | 全局状态管理组件,集成数据查询、国际化和错误处理。 |
应用主界面通过模块化的设计和清晰的结构,为用户提供了直观且高效的交互体验。它将导航、内容展示和状态管理有机结合,构成了 Umami 应用的核心框架。通过 Next.js 布局系统和 React Context,主界面实现了良好的可维护性和扩展性,为后续功能开发奠定了坚实基础。
数据查询模块
简介
数据查询模块是项目中负责从数据库中提取、统计和分析用户行为数据的核心部分。该模块支持多种数据库(如 PostgreSQL/Prisma 和 ClickHouse),并根据不同的业务需求提供多样化的查询功能。模块涵盖了页面浏览、事件追踪、用户行为分析、收入统计等多个方面,为前端展示和数据分析提供统一的数据接口。
详细章节
报表查询
报表查询模块负责生成各种业务报表,如流量归因、漏斗分析、目标达成情况、用户行为洞察、用户访问路径、用户留存率、收入数据等。
流量归因分析
getAttribution
函数用于获取网站流量归因数据,支持按时间范围、归因模型、转化步骤和货币单位等条件筛选。
漏斗分析
getFunnel
函数实现漏斗分析功能,支持 URL 和事件作为漏斗步骤,并兼容通配符匹配。
目标达成情况
getGoals
函数用于统计目标达成情况,如 URL、事件或事件数据的完成次数。
用户行为洞察
getInsights
函数用于提取用户行为洞察数据,支持灵活字段选择与过滤条件组合。
用户访问路径
getJourney
函数用于分析用户访问路径,支持事件序列统计。
用户留存率
getRetention
函数用于计算用户留存率,支持新增用户队列、回访记录等分析。
收入数据
getRevenue
函数用于查询网站收入数据,支持时间、国家、货币维度的汇总。
收入货币类型
getRevenueValues
函数用于查询特定网站在指定日期范围内的所有唯一货币类型。
UTM 参数统计
getUTM
函数用于获取 UTM 参数统计信息,按 URL 查询参数分组统计事件数量。
页面浏览查询
页面浏览查询模块负责获取页面浏览指标和统计数据。
页面浏览指标
getPageviewMetrics
函数用于获取页面浏览指标,支持入口页、出口页或 referrer_domain 的统计。
页面浏览统计
getPageviewStats
函数用于获取页面浏览统计数据,支持按时间粒度统计页面浏览量。
事件查询
事件查询模块负责获取事件数据、事件属性、事件统计等信息。
事件数据
getEventDataEvents
函数用于获取网站事件及其属性数据。
事件字段
getEventDataFields
函数用于从事件中提取字段信息。
事件属性
getEventDataProperties
函数用于从事件中提取属性信息。
事件统计
getEventDataStats
函数用于统计事件数量、属性数量和记录总数。
事件使用情况
getEventDataUsage
函数用于查询事件数据使用情况。
事件属性值
getEventDataValues
函数用于提取特定属性值及其出现次数。
事件指标
getEventMetrics
函数用于获取事件指标数据。
事件统计数据
getEventStats
函数用于获取网站事件统计数据。
事件使用统计
getEventUsage
函数用于查询网站事件使用情况。
网站事件
getWebsiteEvents
函数用于获取网站事件数据。
事件保存
事件保存模块负责将事件数据保存到数据库中。
保存事件数据
saveEventData
函数用于将事件数据保存到 Prisma 和 ClickHouse 数据库。
保存事件
saveEvent
函数用于保存用户行为事件数据。
保存收入
saveRevenue
函数用于保存收入事件数据。
Mermaid图
查询模块架构

表格
主要功能或组件及其描述
功能/组件 | 描述 |
---|---|
报表查询 | 生成各种业务报表,如流量归因、漏斗分析等 |
页面浏览查询 | 获取页面浏览指标和统计数据 |
事件查询 | 获取事件数据、事件属性、事件统计等信息 |
事件保存 | 将事件数据保存到数据库中 |
API 接口参数、类型和描述
接口名称 | 参数 | 类型 | 描述 |
---|---|---|---|
getAttribution | websiteId, dateRange, model, steps, currency | string, object, string, array, string | 获取网站流量归因数据 |
getFunnel | websiteId, dateRange, steps | string, object, array | 实现漏斗分析功能 |
getGoals | websiteId, dateRange, goals | string, object, array | 统计目标达成情况 |
getInsights | websiteId, dateRange, fields | string, object, array | 提取用户行为洞察数据 |
getJourney | websiteId, dateRange, steps | string, object, array | 分析用户访问路径 |
getRetention | websiteId, dateRange | string, object | 计算用户留存率 |
getRevenue | websiteId, dateRange | string, object | 查询网站收入数据 |
getRevenueValues | websiteId, dateRange | string, object | 查询特定网站在指定日期范围内的所有唯一货币类型 |
getUTM | websiteId, dateRange | string, object | 获取 UTM 参数统计信息 |
getPageviewMetrics | websiteId, type, filters, page | string, string, object, object | 获取页面浏览指标 |
getPageviewStats | websiteId, dateRange, unit | string, object, string | 获取页面浏览统计数据 |
getEventDataEvents | websiteId, filters | string, object | 获取网站事件及其属性数据 |
getEventDataFields | websiteId, filters | string, object | 从事件中提取字段信息 |
getEventDataProperties | websiteId, filters | string, object | 从事件中提取属性信息 |
getEventDataStats | websiteId, filters | string, object | 统计事件数量、属性数量和记录总数 |
getEventDataUsage | websiteIds, dateRange | array, object | 查询事件数据使用情况 |
getEventDataValues | websiteId, filters | string, object | 提取特定属性值及其出现次数 |
getEventMetrics | websiteId, filters | string, object | 获取事件指标数据 |
getEventStats | websiteId, filters | string, object | 获取网站事件统计数据 |
getEventUsage | websiteIds, dateRange | array, object | 查询网站事件使用情况 |
getWebsiteEvents | websiteId, filters | string, object | 获取网站事件数据 |
saveEventData | data | object | 将事件数据保存到 Prisma 和 ClickHouse 数据库 |
saveEvent | args | object | 保存用户行为事件数据 |
saveRevenue | data | object | 保存收入事件数据 |
代码片段
getAttribution
async function getAttribution(websiteId: string, dateRange: { startDate: Date; endDate: Date }, model: string, steps: any[], currency: string): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange, model, steps, currency);
} else {
return relationalQuery(websiteId, dateRange, model, steps, currency);
}
}
getFunnel
async function getFunnel(websiteId: string, dateRange: { startDate: Date; endDate: Date }, steps: any[]): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange, steps);
} else {
return relationalQuery(websiteId, dateRange, steps);
}
}
getGoals
async function getGoals(websiteId: string, dateRange: { startDate: Date; endDate: Date }, goals: any[]): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange, goals);
} else {
return relationalQuery(websiteId, dateRange, goals);
}
}
getInsights
async function getInsights(websiteId: string, dateRange: { startDate: Date; endDate: Date }, fields: any[]): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange, fields);
} else {
return relationalQuery(websiteId, dateRange, fields);
}
}
getJourney
async function getJourney(websiteId: string, dateRange: { startDate: Date; endDate: Date }, steps: any[]): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange, steps);
} else {
return relationalQuery(websiteId, dateRange, steps);
}
}
getRetention
async function getRetention(websiteId: string, dateRange: { startDate: Date; endDate: Date }): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange);
} else {
return relationalQuery(websiteId, dateRange);
}
}
getRevenue
async function getRevenue(websiteId: string, dateRange: { startDate: Date; endDate: Date }): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange);
} else {
return relationalQuery(websiteId, dateRange);
}
}
getRevenueValues
async function getRevenueValues(websiteId: string, dateRange: { startDate: Date; endDate: Date }): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange);
} else {
return relationalQuery(websiteId, dateRange);
}
}
getUTM
async function getUTM(websiteId: string, dateRange: { startDate: Date; endDate: Date }): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange);
} else {
return relationalQuery(websiteId, dateRange);
}
}
getPageviewMetrics
async function getPageviewMetrics(websiteId: string, type: string, filters: any, page: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, type, filters, page);
} else {
return relationalQuery(websiteId, type, filters, page);
}
}
getPageviewStats
async function getPageviewStats(websiteId: string, dateRange: { startDate: Date; endDate: Date }, unit: string): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, dateRange, unit);
} else {
return relationalQuery(websiteId, dateRange, unit);
}
}
getEventDataEvents
async function getEventDataEvents(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventDataFields
async function getEventDataFields(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventDataProperties
async function getEventDataProperties(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventDataStats
async function getEventDataStats(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventDataUsage
async function getEventDataUsage(websiteIds: string[], dateRange: { startDate: Date; endDate: Date }): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteIds, dateRange);
} else {
return relationalQuery(websiteIds, dateRange);
}
}
getEventDataValues
async function getEventDataValues(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventMetrics
async function getEventMetrics(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventStats
async function getEventStats(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
getEventUsage
async function getEventUsage(websiteIds: string[], dateRange: { startDate: Date; endDate: Date }): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteIds, dateRange);
} else {
return relationalQuery(websiteIds, dateRange);
}
}
getWebsiteEvents
async function getWebsiteEvents(websiteId: string, filters: any): Promise<any[]> {
if (isClickHouse()) {
return clickhouseQuery(websiteId, filters);
} else {
return relationalQuery(websiteId, filters);
}
}
saveEventData
async function saveEventData(data: any): Promise<void> {
if (isClickHouse()) {
await clickhouseQuery(data);
} else {
await relationalQuery(data);
}
}
saveEvent
async function saveEvent(args: any): Promise<void> {
if (isClickHouse()) {
await clickhouseQuery(args);
} else {
await relationalQuery(args);
}
}
saveRevenue
async function saveRevenue(data: any): Promise<void> {
if (isClickHouse()) {
await clickhouseQuery(data);
} else {
await relationalQuery(data);
}
}
结论/总结
数据查询模块是项目中不可或缺的一部分,它提供了从数据库中提取、统计和分析用户行为数据的功能。通过支持多种数据库和提供多样化的查询接口,该模块为前端展示和数据分析提供了强大的支持。
网站模块
简介
网站模块是项目的核心部分,负责处理与网站相关的所有数据和操作。它提供了丰富的 API 接口,用于获取网站的访问统计、事件数据、会话信息、实时数据等。此外,该模块还支持网站管理功能,如网站信息的增删改查、数据导出、所有权转移等。
网站模块通过 RESTful API 与前端进行交互,确保数据的安全性和一致性。模块中的每个 API 接口都经过严格的权限验证,以确保只有授权用户才能访问相关数据。同时,模块还提供了实时数据展示功能,帮助用户实时监控网站的访问情况。
详细章节
API 接口服务
网站模块提供了一系列 API 接口,用于获取网站的各种数据。这些接口包括获取网站信息、访问统计、事件数据、会话信息等。每个接口都经过严格的权限验证,确保数据的安全性。
获取网站信息
- 接口名称:
GET /api/websites/[websiteId]
- 接口描述: 获取指定网站的信息。
- 参数:
websiteId
: 网站 ID。
获取网站活跃访客信息
- 接口名称:
GET /api/websites/[websiteId]/active
- 接口描述: 获取指定网站的活跃访客信息。
- 参数:
websiteId
: 网站 ID。
获取网站日期范围
- 接口名称:
GET /api/websites/[websiteId]/daterange
- 接口描述: 获取指定网站的日期范围。
- 参数:
websiteId
: 网站 ID。
获取网站事件数据
- 接口名称:
GET /api/websites/[websiteId]/event-data/events
- 接口描述: 获取指定网站的事件数据。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站事件数据字段
- 接口名称:
GET /api/websites/[websiteId]/event-data/fields
- 接口描述: 获取指定网站在特定时间范围内的事件数据字段。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站事件属性
- 接口名称:
GET /api/websites/[websiteId]/event-data/properties
- 接口描述: 获取指定网站的事件属性。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。propertyName
: 属性名称。
获取网站事件数据统计
- 接口名称:
GET /api/websites/[websiteId]/event-data/stats
- 接口描述: 获取指定网站的事件数据统计。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站事件数据值
- 接口名称:
GET /api/websites/[websiteId]/event-data/values
- 接口描述: 获取指定网站的事件数据值。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。propertyName
: 属性名称。
获取网站事件
- 接口名称:
GET /api/websites/[websiteId]/events
- 接口描述: 获取指定网站的事件。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站事件统计数据
- 接口名称:
GET /api/websites/[websiteId]/events/series
- 接口描述: 获取指定网站的事件统计数据。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
导出网站数据
- 接口名称:
GET /api/websites/[websiteId]/export
- 接口描述: 导出指定网站的数据。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站访问指标
- 接口名称:
GET /api/websites/[websiteId]/metrics
- 接口描述: 获取指定网站的访问指标。
- 参数:
websiteId
: 网站 ID。type
: 指标类型(session、event、pageview、channel)。startAt
: 开始时间。endAt
: 结束时间。
获取网站页面浏览量
- 接口名称:
GET /api/websites/[websiteId]/pageviews
- 接口描述: 获取指定网站的页面浏览量。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。unit
: 时间单位。timezone
: 时区。
获取网站报告
- 接口名称:
GET /api/websites/[websiteId]/reports
- 接口描述: 获取指定网站的报告。
- 参数:
websiteId
: 网站 ID。page
: 页码。pageSize
: 每页大小。
重置网站数据
- 接口名称:
POST /api/websites/[websiteId]/reset
- 接口描述: 重置指定网站的数据。
- 参数:
websiteId
: 网站 ID。
更新网站信息
- 接口名称:
POST /api/websites/[websiteId]
- 接口描述: 更新指定网站的信息。
- 参数:
websiteId
: 网站 ID。name
: 网站名称。domain
: 网站域名。
删除网站
- 接口名称:
DELETE /api/websites/[websiteId]
- 接口描述: 删除指定网站。
- 参数:
websiteId
: 网站 ID。
获取网站分段
- 接口名称:
GET /api/websites/[websiteId]/segments
- 接口描述: 获取指定网站的分段。
- 参数:
websiteId
: 网站 ID。
创建网站分段
- 接口名称:
POST /api/websites/[websiteId]/segments
- 接口描述: 创建指定网站的分段。
- 参数:
websiteId
: 网站 ID。name
: 分段名称。filters
: 分段过滤条件。
获取网站分段信息
- 接口名称:
GET /api/websites/[websiteId]/segments/[segmentId]
- 接口描述: 获取指定网站分段的信息。
- 参数:
websiteId
: 网站 ID。segmentId
: 分段 ID。
更新网站分段
- 接口名称:
POST /api/websites/[websiteId]/segments/[segmentId]
- 接口描述: 更新指定网站分段的信息。
- 参数:
websiteId
: 网站 ID。segmentId
: 分段 ID。name
: 分段名称。filters
: 分段过滤条件。
删除网站分段
- 接口名称:
DELETE /api/websites/[websiteId]/segments/[segmentId]
- 接口描述: 删除指定网站分段。
- 参数:
websiteId
: 网站 ID。segmentId
: 分段 ID。
获取网站会话数据属性
- 接口名称:
GET /api/websites/[websiteId]/session-data/properties
- 接口描述: 获取指定网站的会话数据属性。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。propertyName
: 属性名称。
获取网站会话数据值
- 接口名称:
GET /api/websites/[websiteId]/session-data/values
- 接口描述: 获取指定网站的会话数据值。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。propertyName
: 属性名称。
获取网站会话
- 接口名称:
GET /api/websites/[websiteId]/sessions
- 接口描述: 获取指定网站的会话。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站会话活动
- 接口名称:
GET /api/websites/[websiteId]/sessions/[sessionId]/activity
- 接口描述: 获取指定网站会话的活动。
- 参数:
websiteId
: 网站 ID。sessionId
: 会话 ID。
获取网站会话属性
- 接口名称:
GET /api/websites/[websiteId]/sessions/[sessionId]/properties
- 接口描述: 获取指定网站会话的属性。
- 参数:
websiteId
: 网站 ID。sessionId
: 会话 ID。
获取网站会话信息
- 接口名称:
GET /api/websites/[websiteId]/sessions/[sessionId]
- 接口描述: 获取指定网站会话的信息。
- 参数:
websiteId
: 网站 ID。sessionId
: 会话 ID。
获取网站会话统计数据
- 接口名称:
GET /api/websites/[websiteId]/sessions/stats
- 接口描述: 获取指定网站的会话统计数据。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站每周会话
- 接口名称:
GET /api/websites/[websiteId]/sessions/weekly
- 接口描述: 获取指定网站每周的会话。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
获取网站统计数据
- 接口名称:
GET /api/websites/[websiteId]/stats
- 接口描述: 获取指定网站的统计数据。
- 参数:
websiteId
: 网站 ID。startAt
: 开始时间。endAt
: 结束时间。
转移网站所有权
- 接口名称:
POST /api/websites/[websiteId]/transfer
- 接口描述: 转移指定网站的所有权。
- 参数:
websiteId
: 网站 ID。userId
: 用户 ID。teamId
: 团队 ID。
获取网站值
- 接口名称:
GET /api/websites/[websiteId]/values
- 接口描述: 获取指定网站的值。
- 参数:
websiteId
: 网站 ID。type
: 值类型。startAt
: 开始时间。endAt
: 结束时间。search
: 搜索关键字。
实时数据展示
网站模块还提供了实时数据展示功能,帮助用户实时监控网站的访问情况。实时数据展示包括国家分布、关键指标、实时日志、URL 和来源信息等。
实时国家分布
- 组件名称:
RealtimeCountries
- 功能描述: 展示按国家划分的访客信息。
- 相关文件:
src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx
src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.module.css
实时关键指标
- 组件名称:
RealtimeHeader
- 功能描述: 展示访问量、访客数等关键指标卡片。
- 相关文件:
src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx
src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.module.css
实时首页
- 组件名称:
RealtimeHome
- 功能描述: 加载用户网站列表并跳转到第一个网站的实时页面。
- 相关文件:
src/app/(main)/websites/[websiteId]/realtime/RealtimeHome.tsx
实时日志
- 组件名称:
RealtimeLog
- 功能描述: 展示网站实时日志。
- 相关文件:
src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.module.css
实时 URL 和来源
- 组件名称:
RealtimeUrls
- 功能描述: 展示网站实时 URL 和来源信息。
- 相关文件:
src/app/(main)/websites/[websiteId]/realtime/RealtimeUrls.tsx
网站实时页面
- 组件名称:
WebsiteRealtimePage
- 功能描述: 展示网站实时数据的页面组件。
- 相关文件:
src/app/(main)/websites/[websiteId]/realtime/WebsiteRealtimePage.tsx
Mermaid 图
网站模块架构图

表格
主要功能或组件及其描述
功能/组件 | 描述 |
---|---|
获取网站信息 | 获取指定网站的信息 |
获取网站活跃访客 | 获取指定网站的活跃访客信息 |
获取网站日期范围 | 获取指定网站的日期范围 |
获取网站事件数据 | 获取指定网站的事件数据 |
获取网站事件数据字段 | 获取指定网站在特定时间范围内的事件数据字段 |
获取网站事件属性 | 获取指定网站的事件属性 |
获取网站事件数据统计 | 获取指定网站的事件数据统计 |
获取网站事件数据值 | 获取指定网站的事件数据值 |
获取网站事件 | 获取指定网站的事件 |
获取网站事件统计数据 | 获取指定网站的事件统计数据 |
导出网站数据 | 导出指定网站的数据 |
获取网站访问指标 | 获取指定网站的访问指标 |
获取网站页面浏览量 | 获取指定网站的页面浏览量 |
获取网站报告 | 获取指定网站的报告 |
重置网站数据 | 重置指定网站的数据 |
更新网站信息 | 更新指定网站的信息 |
删除网站 | 删除指定网站 |
获取网站分段 | 获取指定网站的分段 |
创建网站分段 | 创建指定网站的分段 |
获取网站分段信息 | 获取指定网站分段的信息 |
更新网站分段 | 更新指定网站分段的信息 |
删除网站分段 | 删除指定网站分段 |
获取网站会话数据属性 | 获取指定网站的会话数据属性 |
获取网站会话数据值 | 获取指定网站的会话数据值 |
获取网站会话 | 获取指定网站的会话 |
获取网站会话活动 | 获取指定网站会话的活动 |
获取网站会话属性 | 获取指定网站会话的属性 |
获取网站会话信息 | 获取指定网站会话的信息 |
获取网站会话统计数据 | 获取指定网站的会话统计数据 |
获取网站每周会话 | 获取指定网站每周的会话 |
获取网站统计数据 | 获取指定网站的统计数据 |
转移网站所有权 | 转移指定网站的所有权 |
获取网站值 | 获取指定网站的值 |
实时国家分布 | 展示按国家划分的访客信息 |
实时关键指标 | 展示访问量、访客数等关键指标卡片 |
实时首页 | 加载用户网站列表并跳转到第一个网站的实时页面 |
实时日志 | 展示网站实时日志 |
实时 URL 和来源 | 展示网站实时 URL 和来源信息 |
网站实时页面 | 展示网站实时数据的页面组件 |
结论/总结
网站模块是项目的核心部分,提供了丰富的 API 接口和实时数据展示功能。通过这些接口和组件,用户可以方便地获取网站的各种数据,并实时监控网站的访问情况。模块中的每个接口都经过严格的权限验证,确保数据的安全性。同时,模块还支持网站管理功能,如网站信息的增删改查、数据导出、所有权转移等,为用户提供了一站式的网站管理解决方案。
本网站提供的所有AI生成内容均基于人工智能技术和大语言模型算法,根据用户输入指令自动生成。生成内容不代表本网站观点,亦不构成任何形式的专业建议。本公司对生成内容的准确性、完整性、适用性及合法性不作明示或默示的保证,用户应对生成内容自行判断并承担全部使用风险。