Skip to content

技术架构

ValPoint 采用现代化的前后端分离架构,基于 React + Supabase 构建。

🏗️ 前端架构

技术栈

技术版本用途
React18.xUI 框架
TypeScript5.x类型系统
Vite5.x构建工具
VitePress1.x文档系统
Tailwind CSS3.x样式框架
Leaflet1.9.x地图库
Lucide React-图标库

目录结构

以下为核心目录概览,完整结构请参考源码。

src/
├── apps/                # MPA 应用入口
│   ├── admin/           # 管理后台
│   ├── shared/          # 共享库(首页)
│   └── user/            # 个人库

├── features/            # 功能模块
│   └── lineups/         # 点位管理核心功能

├── components/          # 通用 React 组件 (31+)
│   ├── AlertModal.tsx   # 通用弹窗
│   ├── Icon.tsx         # 图标组件
│   └── ...

├── hooks/               # 自定义 Hooks (14+)
│   ├── useValorantData.ts
│   ├── useLineups.ts
│   └── ...

├── lib/                 # 库封装 (21+)
│   ├── supabaseClient.ts
│   ├── imageBed.ts
│   └── ...

├── services/            # 服务层
├── types/               # TypeScript 类型
├── utils/               # 工具函数
├── constants/           # 常量配置
├── data/                # 静态数据
├── styles/              # 样式文件

├── main.tsx             # 主入口
└── index.css            # 全局样式

组件层次

项目采用 MPA 架构,三个独立应用共享通用组件。

┌─────────────────────────────────────────────────────┐
│                    MPA 入口                          │
├──────────────┬───────────────┬──────────────────────┤
│ index.html   │ user.html     │ admin.html           │
│ (共享库)     │ (个人库)      │ (管理后台)           │
└──────┬───────┴───────┬───────┴──────────┬───────────┘
       │               │                  │
       ▼               ▼                  ▼
  SharedMainView   UserMainView     AdminLayout
       │               │                  │
       ▼               ▼                  ▼
  ┌────────────────────────────────────────────┐
  │              通用组件层                     │
  │  LeafletMap / ViewerModal / EditorModal   │
  │  Icon / AlertModal / AuthorLinksBar       │
  └────────────────────────────────────────────┘

VitePress 文档系统

项目内置了基于 VitePress 的文档系统,与主应用统一部署。

目录结构

docs/
├── .vitepress/
│   ├── config.ts        # VitePress 配置
│   └── theme/           # 自定义主题
├── guide/               # 用户指南
├── dev/                 # 开发文档
├── public/              # 静态资源
└── index.md             # 文档首页

构建流程

bash
# 开发环境(需同时运行)
npm run dev         # 主应用 localhost:3208
npm run docs:dev    # VitePress localhost:5173

# 生产构建(统一构建脚本)
npm run build:all   # 主应用 + 文档一起构建

访问路径

环境访问方式
开发localhost:3208/wiki/ (通过 Vite 代理)
生产yoursite.com/wiki/ (静态文件)

技术要点

  • Base 路径: VitePress 配置 base: '/wiki/'
  • 代理配置: Vite 开发服务器代理 /wiki/* 到 VitePress
  • 构建合并: build-all.js 将 VitePress 输出复制到 dist/wiki/

🏗️ 后端架构

Supabase 服务

PostgreSQL 数据库

系统使用 7 张核心数据表:

表名用途
user_profiles用户资料(角色、权限、下载统计)
valorant_lineups个人点位库
valorant_shared共享中心库
lineup_submissions点位投稿审核
user_daily_downloads每日下载限制
system_settings系统设置(图床、投稿开关)
download_logs下载日志记录

用户资料表 (user_profiles)

sql
CREATE TABLE user_profiles (
  id UUID PRIMARY KEY REFERENCES auth.users(id),
  email TEXT,
  nickname TEXT,
  avatar TEXT,
  custom_id TEXT UNIQUE,                    -- 自定义用户 ID
  role TEXT CHECK (role IN ('user', 'admin', 'super_admin')),
  is_banned BOOLEAN DEFAULT false,
  ban_reason TEXT,
  download_count BIGINT DEFAULT 0,          -- 累计下载次数
  can_batch_download BOOLEAN DEFAULT false, -- 批量下载权限
  pinned_lineup_ids JSONB DEFAULT '[]',     -- 置顶点位
  subscriptions JSONB DEFAULT '[]',         -- 订阅列表
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

个人点位库 (valorant_lineups)

sql
CREATE TABLE valorant_lineups (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
  title TEXT,
  map_name TEXT,
  agent_name TEXT,
  agent_icon TEXT,
  skill_icon TEXT,
  side TEXT CHECK (side IN ('attack', 'defense')),
  ability_index INTEGER,
  agent_pos JSONB,        -- 地图上角色位置
  skill_pos JSONB,        -- 地图上技能落点位置
  stand_img TEXT,         -- 站位图
  stand_desc TEXT,
  stand2_img TEXT,        -- 站位图2
  stand2_desc TEXT,
  aim_img TEXT,           -- 瞄点图
  aim_desc TEXT,
  aim2_img TEXT,          -- 瞄点图2
  aim2_desc TEXT,
  land_img TEXT,          -- 落点图
  land_desc TEXT,
  source_link TEXT,       -- 来源链接
  cloned_from UUID,       -- 克隆来源
  author_name TEXT,
  author_avatar TEXT,
  author_uid TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

点位投稿审核表 (lineup_submissions)

sql
CREATE TABLE lineup_submissions (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  submitter_id UUID REFERENCES auth.users(id),
  submitter_email TEXT,
  -- 点位信息字段 (同 valorant_lineups)
  status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'approved', 'rejected')),
  reject_reason TEXT,
  reviewed_by TEXT,
  reviewed_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

系统设置表 (system_settings)

sql
CREATE TABLE system_settings (
  id UUID PRIMARY KEY DEFAULT '00000000-0000-0000-0000-000000000001',
  official_oss_config JSONB,           -- 官方图床配置
  submission_enabled BOOLEAN DEFAULT true,
  daily_submission_limit INTEGER DEFAULT 10,
  daily_download_limit INTEGER DEFAULT 50,
  author_links JSONB,                  -- 作者链接(打赏、联系等)
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

Row Level Security (RLS)

sql
-- 个人库:用户只能访问自己的数据
CREATE POLICY "Users can view own lineups"
  ON valorant_lineups FOR SELECT
  USING (auth.uid() = user_id);

-- 共享库:所有人可读,仅管理员可写
CREATE POLICY "Anyone can view shared lineups"
  ON valorant_shared FOR SELECT USING (true);

CREATE POLICY "Only admins can modify shared lineups"
  ON valorant_shared FOR ALL
  USING (public.is_admin());

-- 管理员权限检查函数
CREATE FUNCTION public.is_admin() RETURNS BOOLEAN AS $$
BEGIN
  RETURN EXISTS (
    SELECT 1 FROM user_profiles
    WHERE id = auth.uid() AND role IN ('admin', 'super_admin')
  );
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

Edge Functions

get-video-author

  • 运行时:Deno
  • 用途:解析 B 站和抖音视频作者信息
  • 端点:/functions/v1/get-video-author
  • 方法:POST
  • 请求体:{ "url": "视频链接" }
  • 响应:
    json
    {
      "status": "success",
      "data": {
        "username": "作者昵称",
        "avatar": "头像 URL",
        "user_home_url": "主页链接",
        "is_cover": false,
        "source": "bilibili" | "douyin"
      }
    }

📊 数据库设计

索引设计

sql
-- 个人库索引
CREATE INDEX idx_lineups_user_id ON valorant_lineups(user_id);
CREATE INDEX idx_lineups_map_agent ON valorant_lineups(map_name, agent_name);
CREATE INDEX idx_lineups_side ON valorant_lineups(side);
CREATE INDEX idx_lineups_cloned_from ON valorant_lineups(cloned_from);

-- 共享库索引
CREATE INDEX idx_shared_map_agent ON valorant_shared(map_name, agent_name);
CREATE INDEX idx_shared_source_id ON valorant_shared(source_id);
CREATE INDEX idx_shared_side ON valorant_shared(side);

-- 投稿审核索引
CREATE INDEX idx_submissions_submitter ON lineup_submissions(submitter_id);
CREATE INDEX idx_submissions_status ON lineup_submissions(status);

-- 每日下载索引
CREATE INDEX idx_daily_downloads_lookup ON user_daily_downloads(user_id, date);

-- 下载日志索引
CREATE INDEX idx_download_logs_user_id ON download_logs(user_id);
CREATE INDEX idx_download_logs_created_at ON download_logs(created_at DESC);

-- 用户资料索引
CREATE INDEX idx_user_profiles_email ON user_profiles(email);
CREATE INDEX idx_user_profiles_custom_id ON user_profiles(custom_id);

🔗 第三方集成

图床服务

支持三种云存储服务,配置保存在用户本地:

服务商SDK备注
阿里云 OSSali-oss推荐,国内速度快
腾讯云 COScos-js-sdk-v5AppId 格式需注意
七牛云 Kodoqiniu-js需服务端生成 Token

外部 API

API用途
Valorant API获取英雄/技能/地图数据
Valorant Rotation API获取动态地图池排位状态
B 站 Web API视频作者信息解析(Edge Function)
抖音 HTML 解析视频作者信息解析(Edge Function)

⚡ 性能优化

类别策略
代码分割Vite 自动路由级分割,动态导入大型组件
图片优化上传自动压缩,使用 WebP/PNG,懒加载
缓存策略LocalStorage 配置缓存,浏览器缓存
渲染优化React.memo,useMemo/useCallback
数据库合理索引设计,避免 N+1 查询
CDNVercel 静态资源 + 图床 CDN

🔒 安全设计

类别措施
XSS 防护React 自动转义,避免 dangerouslySetInnerHTML
认证授权Supabase JWT Token,RLS 行级安全
敏感信息环境变量管理,前端不存储密钥
API 限流Supabase 自动限流,每日下载限制

📈 监控和日志

类别工具
后台统计下载日志、用户管理、点位审核
数据库监控Supabase Dashboard
错误日志浏览器 Console,Edge Function 日志

🏗️ 技术选型理由

技术理由
React生态成熟,组件化开发
TypeScript类型安全,减少 Bug
Vite快速构建,HMR 体验好
VitePress文档静态站点,与主应用统一部署
Supabase开箱即用,降低后端成本
Tailwind CSS快速开发,样式一致
Leaflet轻量级地图库,自定义性强

Made with ♥ for Valorant Players