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 环境,包含 umamidbcypress 三个服务。
  • podman/podman-compose.yml:用于 Podman 部署的配置文件,定义了 umamidb 两个服务。
  • 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.servicesystemd 服务配置文件,用于通过 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 表单。
  • 接收 teamIduserIdrole 参数。
  • 通过回调处理保存逻辑。
  • 使用多个自定义 Hook 实现国际化、提示和状态管理。

团队成员编辑表单

该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMemberEditForm.tsx,是一个表单组件。

  • 用于修改成员角色。
  • 接收 teamIduserIdrole
  • 提交时调用 API 更新权限。
  • 结合 useApiuseMutation 处理请求与状态。
  • 支持多语言标签。

团队成员移除按钮

该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMemberRemoveButton.tsx,是一个删除成员按钮组件。

  • 触发确认对话框并调用 API 删除用户。
  • 使用 ModalTriggerConfirmationForm 实现交互逻辑。
  • 依赖多个 Hook 管理请求与状态更新。

团队成员数据表格容器

该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMembersDataTable.tsx,是表格容器组件。

  • 负责获取并展示团队成员数据。
  • 通过 useTeamMembers(teamId) 获取数据。
  • 渲染 DataTable 及其子组件 TeamMembersTable
  • 实现数据展示与交互分离。

团队成员页面组件

该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMembersPage.tsx,是客户端页面组件。

  • 根据用户权限决定是否允许编辑操作。
  • 结合 TeamContextuseLoginuseMessages 控制界面行为。
  • 渲染 TeamMembersDataTable 展示成员列表。

团队成员表格组件

该组件位于 src/app/(main)/teams/[teamId]/settings/members/TeamMembersTable.tsx,是表格组件。

  • 展示成员信息并提供编辑和移除操作。
  • 根据 allowEdit 条件渲染对应按钮。
  • 禁止对团队所有者或当前用户进行操作。
  • 使用 GridTable 构建结构。

Mermaid图

团队模块架构图

团队管理接口流程图

团队成员管理接口流程图

用户加入团队接口流程图

表格

主要功能或组件及其描述

功能/组件描述
团队管理接口提供对单个团队的查看、更新、删除操作
团队成员管理接口管理团队中的用户列表和特定用户
团队网站信息接口查询团队关联的网站信息
用户加入团队接口处理用户通过访问码加入团队的请求
团队成员管理页面展示团队成员信息的 Next.js 页面组件
团队成员编辑按钮编辑成员角色的按钮组件
团队成员编辑表单修改成员角色的表单组件
团队成员移除按钮删除成员的按钮组件
团队成员数据表格容器获取并展示团队成员数据的容器组件
团队成员页面组件客户端页面组件,控制界面行为
团队成员表格组件展示成员信息并提供操作的表格组件

API 接口参数、类型和描述

接口方法参数类型描述
/teams/{teamId}GETteamIdstring团队ID
/teams/{teamId}POSTteamId, bodystring, object团队ID, 请求体
/teams/{teamId}DELETEteamIdstring团队ID
/teams/{teamId}/usersGETteamIdstring团队ID
/teams/{teamId}/usersPOSTteamId, bodystring, object团队ID, 请求体
/teams/{teamId}/users/{userId}GETteamId, userIdstring, string团队ID, 用户ID
/teams/{teamId}/users/{userId}POSTteamId, userId, bodystring, string, object团队ID, 用户ID, 请求体
/teams/{teamId}/users/{userId}DELETEteamId, userIdstring, string团队ID, 用户ID
/teams/{teamId}/websitesGETteamId, querystring, object团队ID, 查询参数
/teams/joinPOSTbodyobject请求体,包含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 管理网站相关的 dateRangedateCompare 状态。

关键函数

  • 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 模块的状态管理
时间戳记录记录事件或操作的最新发生时间
版本检查逻辑管理应用版本检查逻辑
网站状态管理管理网站相关的 dateRangedateCompare 状态

状态字段详情

文件状态字段类型描述
app.tslocalestring当前语言设置
app.tsthemestring当前主题设置
app.tstimezonestring当前时区设置
app.tsdateRangeobject当前日期范围
app.tsshareTokenstring/null分享令牌
app.tsuserobject/null用户信息
app.tsconfigobject/null应用配置
dashboard.tsshowChartsboolean是否显示图表
dashboard.tslimitnumber网站数量限制
dashboard.tswebsiteOrderarray网站排序
dashboard.tswebsiteActivearray激活的网站
dashboard.tseditingboolean是否处于编辑状态
dashboard.tsisEditedboolean是否已编辑
version.tscurrentstring当前版本
version.tslateststring/null最新版本
version.tshasUpdateboolean是否有更新
version.tscheckedboolean是否已检查
version.tsreleaseUrlstring/null发布链接

结论/总结

状态管理模块通过 Zustand 实现了全局状态的集中管理,涵盖了从应用配置到特定功能模块的状态管理。通过提供基础的状态写入能力、仪表盘状态管理、时间戳记录、版本检查逻辑和网站状态管理,模块确保了应用各组件之间的数据一致性与响应式更新能力。这些模块协同工作,为整个应用提供了稳定、高效的状态管理解决方案。


UI组件库

简介

UI组件库是项目中用于构建用户界面的核心模块,涵盖了布局、输入控件和图表三大类组件。这些组件通过模块化的CSS和React实现,提供了高度可复用和可定制的UI元素,支持响应式设计和国际化。布局组件如GridMenuLayoutPage提供了页面结构的基础;输入控件如DateFilterDownloadButtonLanguageButton增强了用户交互;图表组件如BarChartPieChartBubbleChart则用于数据可视化。

布局组件

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:接收itemschildren,通过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:接收classNameerrorisLoadingchildren,优先处理错误和加载状态。
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:接收startDateendDate等属性,通过Dropdown显示选项,点击“自定义”弹出ModalDatePickerForm表单。
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:接收filenamedata属性,结合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,使用useRefuseState管理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组件用于渲染饼图或环形图,支持piedoughnut类型。

组件实现

  • 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:接收tooltipunitcurrency作为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柱状图工具提示组件

图表组件配置选项

配置项类型描述
typestring图表类型(bar, pie, doughnut, bubble)
dataobject图表数据
optionsobject图表配置选项
unitstring数据单位
stackedboolean是否堆叠显示
currencystring货币格式

结论

UI组件库通过模块化的CSS和React实现,提供了高度可复用和可定制的UI元素,支持响应式设计和国际化。布局组件如GridMenuLayoutPage提供了页面结构的基础;输入控件如DateFilterDownloadButtonLanguageButton增强了用户交互;图表组件如BarChartPieChartBubbleChart则用于数据可视化。这些组件共同构成了项目中用户界面的核心部分,确保了良好的用户体验和高度的可维护性。图表组件基于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/loginusernamestring用户名
passwordstring密码
POST /api/me/passwordcurrentPasswordstring当前密码
newPasswordstring新密码
GET /api/users/[userId]/teamsuserIdstring用户ID

技术实现细节

登录认证流程

用户登录接口采用多层安全验证机制。首先通过 zod 进行输入数据格式校验,确保用户名和密码符合预期格式。随后调用 parseRequest 解析请求数据并跳过默认认证流程。系统通过 getUserByUsername 从数据库获取用户信息,再使用 checkPassword 验证用户提供的密码是否正确。

在认证成功后,系统会根据 Redis 配置选择不同的令牌生成策略。如果 Redis 可用,则调用 saveAuth 将认证信息存储到 Redis 中;否则使用 createSecureToken 生成 JWT 令牌。最终返回包含认证令牌和用户基础信息的 JSON 响应。

密码安全处理

密码更新接口实施了严格的安全措施来保护用户密码信息。接口首先使用 zod 校验当前密码和新密码的格式,确保它们符合安全要求。通过 parseRequest 解析请求数据,如果校验失败则立即返回错误响应。

系统从认证信息中提取用户 ID,然后查询数据库验证用户提供的当前密码是否正确。只有在当前密码验证通过的情况下,系统才会对新密码进行哈希处理,并调用 updateUser 函数更新数据库中的密码字段。整个过程确保了密码更新的安全性和数据一致性。

权限控制机制

用户团队信息接口实现了细粒度的权限控制。接口通过 parseRequest 解析分页参数,如果解析失败则返回错误响应。系统提取请求中的 userId 参数,并进行权限校验,只允许当前用户或管理员访问该接口。

权限校验通过后,系统调用 getUserTeams(userId, query) 函数查询用户所属的团队信息。这种设计确保了用户只能访问自己或其管理范围内的用户团队信息,防止了未授权的数据访问。

数据流分析

登录数据流

  1. 用户提交登录请求,包含用户名和密码
  2. 系统使用 zod 验证输入数据格式
  3. parseRequest 解析请求并跳过默认认证
  4. getUserByUsername 从数据库获取用户信息
  5. checkPassword 验证密码正确性
  6. 根据 Redis 状态选择认证存储策略
  7. 生成认证令牌并返回用户信息

密码更新数据流

  1. 用户提交密码更新请求,包含当前密码和新密码
  2. 使用 zod 校验密码格式
  3. parseRequest 解析请求数据
  4. 从认证信息获取用户 ID
  5. 数据库验证当前密码
  6. 对新密码进行哈希处理
  7. 调用 updateUser 更新密码
  8. 返回更新后的用户信息

团队信息查询数据流

  1. 用户发起团队信息查询请求
  2. parseRequest 解析分页参数
  3. 提取并验证 userId 参数
  4. 实施权限校验(当前用户或管理员)
  5. 调用 getUserTeams 查询数据
  6. 返回团队信息结果

安全考虑

用户模块在设计和实现过程中充分考虑了安全性。所有接口都采用了输入数据验证机制,防止恶意数据注入。密码处理采用哈希算法,确保密码在存储和传输过程中的安全性。权限控制机制防止了未授权访问,确保用户只能访问其权限范围内的数据。

认证令牌的生成和存储采用了灵活的策略,既支持基于 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 来获取和管理状态信息。该上下文提供统一的数据源和状态更新方法,确保组件间数据同步和交互一致性。

数据获取与处理流程

  1. 目标报告
  • GoalsParameters 通过 ReportContext 获取报告状态
  • 用户添加或编辑目标后,调用回调提交数据
  • GoalsChart 从上下文中获取数据并计算完成百分比
  1. 用户留存报告
  • RetentionParameters 通过 ReportContext 获取状态信息
  • 用户配置日期范围后,触发查询执行
  • RetentionTable 从上下文中获取数据并渲染表格
  1. 漏斗分析报告
  • FunnelParameters 依赖 ReportContextuseMessages
  • 用户添加、编辑或删除漏斗步骤后,更新上下文状态
  • FunnelChart 从上下文中获取数据并动态渲染步骤卡片

表单提交与参数更新

  • GoalsAddForm:维护输入值状态,调用回调提交数据
  • RetentionParameters:包含 handleSubmithandleDateChange 核心函数
  • FunnelStepAddForm:支持回车键或按钮提交,确保输入有效性后触发回调

总结

报告模块通过目标报告、用户留存报告和漏斗分析报告三个子模块,全面覆盖用户行为数据的分析需求。每个子模块均采用组件化设计,结合模块化 CSS 和国际化支持,确保界面统一且功能完整。通过 ReportContext 管理状态,模块间数据流清晰,便于维护和扩展。各组件通过上下文共享状态和方法,实现了高效的数据交互和视图更新。表单提交和参数更新机制保证了用户配置的实时生效,提升了用户体验。整个模块设计遵循 Next.js 页面规范,具有良好的可维护性和可扩展性。


工具模块

工具模块是项目中多个功能模块的基础支撑,提供通用的辅助函数、数据处理逻辑、认证机制、数据库交互、消息队列集成等。这些工具模块旨在提升代码复用性、降低耦合度,并为上层业务逻辑提供统一的接口和标准化的处理流程。

认证与权限控制

功能概述

认证与权限控制模块(auth.ts)负责系统的身份验证和权限管理。它使用 bcrypt 进行密码加密验证,JWT 令牌解析,Redis 缓存存储,并提供多个以 can... 命名的异步权限判断函数,支持基于角色的权限控制(RBAC)。

核心函数

  • checkAuth(): 验证请求中的 token 并返回用户信息。
  • saveAuth(): 存储认证信息并生成 Token。
  • can...(): 异步权限判断函数。

数据流

表格:认证与权限控制函数

函数名描述参数返回值
checkAuth()验证请求中的 token 并返回用户信息token用户信息
saveAuth()存储认证信息并生成 TokenuserInfoToken
can...()异步权限判断函数userId, permissionboolean

数据处理与格式化

功能概述

数据处理与格式化模块(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()解析请求体requestJSON 对象
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()将十六进制颜色转换为RGBhexRGB对象
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/v5version, namespace, nameUUID

日期处理工具

功能概述

日期处理工具模块(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()提取客户端 IPheadersIP地址
getDevice()判断设备类型screen, os设备类型
getLocation()获取地理位置ip, headers, hasPayloadIP地理位置信息
getClientInfo()整合客户端信息request, payload客户端信息对象
hasBlockedIp()检查 IP 是否在黑名单clientIpboolean

数据过滤工具

功能概述

数据过滤工具模块(filters.ts)包含多个数据过滤函数,用于统计分析场景,如流量来源、URL 路径等数据聚合。

核心函数

  • urlFilter(data): 按字段分组并累加值。
  • refFilter(data): 提取域名并保留原始 URL。
  • emptyFilter(data): 过滤空值。
  • percentFilter(data): 计算占比。
  • paramFilter(data): 解析 URL 参数并分组。

数据流

表格:数据过滤工具函数

函数名描述参数返回值
urlFilter()按字段分组并累加值data过滤后的数据
refFilter()提取域名并保留原始 URLdata过滤后的数据
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()生成 JWTpayload, secretJWT令牌
parseToken()解析 JWTtoken, secret解析后的载荷
createSecureToken()加密 JWTpayload, secret加密后的JWT
parseSecureToken()解密 JWTtoken, 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_URLRedis连接URLstring
clientRedis客户端实例RedisClient实例对象
enabled是否启用Redisboolean根据环境变量确定

请求处理工具

功能概述

请求处理工具模块(request.ts)提供 HTTP 请求处理工具函数,包括解析请求体、验证数据、身份认证和提取查询参数,支持 Zod 校验与错误回调,标准化后端接口的请求处理流程。

核心函数

  • getJsonBody(): 解析请求体。
  • parseRequest(): 验证数据。
  • getRequestDateRange(): 提取日期范围。
  • getRequestFilters(): 提取查询过滤器。

数据流

表格:请求处理工具函数

函数名描述参数返回值
getJsonBody()解析请求体requestJSON对象
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字符串枚举
urlSchemaURL校验模式url字符串

本地存储工具

功能概述

本地存储工具模块(storage.ts)封装浏览器本地存储操作,提供 setItem, getItem, removeItem 函数,支持 localStoragesessionStorage,仅在客户端运行,避免 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()构建完整URLbaseUrl, path, params完整URL
safeDecodeURI()安全解码URIuri解码后的URI
safeDecodeURIComponent()安全解码URI组件uriComponent解码后的组件

通用工具函数

功能概述

通用工具函数模块(utils.ts)提供了多个通用工具函数,包括方法扩展、异步延时、数组操作等,这些函数简洁、泛型友好,适合项目中复用。

核心函数

  • hook(): 扩展对象方法,支持前置回调。
  • sleep(): 实现指定毫秒数的异步延时。
  • shuffleArray(): 使用 Fisher-Yates 算法打乱数组。
  • chunkArray(): 按大小分块数组。
  • ensureArray(): 确保输入为数组。

数据流

表格:通用工具函数

函数名描述参数返回值
hook()扩展对象方法,支持前置回调target, methodName, callback
sleep()实现指定毫秒数的异步延时msPromise
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 组件是主界面的入口,负责协调用户登录状态、应用配置和路由路径。它通过 useLoginuseConfigusePathname 获取必要状态,并在加载时显示 <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 接口参数、类型和描述

接口名称参数类型描述
getAttributionwebsiteId, dateRange, model, steps, currencystring, object, string, array, string获取网站流量归因数据
getFunnelwebsiteId, dateRange, stepsstring, object, array实现漏斗分析功能
getGoalswebsiteId, dateRange, goalsstring, object, array统计目标达成情况
getInsightswebsiteId, dateRange, fieldsstring, object, array提取用户行为洞察数据
getJourneywebsiteId, dateRange, stepsstring, object, array分析用户访问路径
getRetentionwebsiteId, dateRangestring, object计算用户留存率
getRevenuewebsiteId, dateRangestring, object查询网站收入数据
getRevenueValueswebsiteId, dateRangestring, object查询特定网站在指定日期范围内的所有唯一货币类型
getUTMwebsiteId, dateRangestring, object获取 UTM 参数统计信息
getPageviewMetricswebsiteId, type, filters, pagestring, string, object, object获取页面浏览指标
getPageviewStatswebsiteId, dateRange, unitstring, object, string获取页面浏览统计数据
getEventDataEventswebsiteId, filtersstring, object获取网站事件及其属性数据
getEventDataFieldswebsiteId, filtersstring, object从事件中提取字段信息
getEventDataPropertieswebsiteId, filtersstring, object从事件中提取属性信息
getEventDataStatswebsiteId, filtersstring, object统计事件数量、属性数量和记录总数
getEventDataUsagewebsiteIds, dateRangearray, object查询事件数据使用情况
getEventDataValueswebsiteId, filtersstring, object提取特定属性值及其出现次数
getEventMetricswebsiteId, filtersstring, object获取事件指标数据
getEventStatswebsiteId, filtersstring, object获取网站事件统计数据
getEventUsagewebsiteIds, dateRangearray, object查询网站事件使用情况
getWebsiteEventswebsiteId, filtersstring, object获取网站事件数据
saveEventDatadataobject将事件数据保存到 Prisma 和 ClickHouse 数据库
saveEventargsobject保存用户行为事件数据
saveRevenuedataobject保存收入事件数据

代码片段

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生成内容均基于人工智能技术和大语言模型算法,根据用户输入指令自动生成。生成内容不代表本网站观点,亦不构成任何形式的专业建议。本公司对生成内容的准确性、完整性、适用性及合法性不作明示或默示的保证,用户应对生成内容自行判断并承担全部使用风险。

《用户使用协议》