技术架构
ValPoint 采用现代化的前后端分离架构,基于 React + Supabase 构建。
🏗️ 前端架构
技术栈
| 技术 | 版本 | 用途 |
|---|---|---|
| React | 18.x | UI 框架 |
| TypeScript | 5.x | 类型系统 |
| Vite | 5.x | 构建工具 |
| VitePress | 1.x | 文档系统 |
| Tailwind CSS | 3.x | 样式框架 |
| Leaflet | 1.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 | 备注 |
|---|---|---|
| 阿里云 OSS | ali-oss | 推荐,国内速度快 |
| 腾讯云 COS | cos-js-sdk-v5 | AppId 格式需注意 |
| 七牛云 Kodo | qiniu-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 查询 |
| CDN | Vercel 静态资源 + 图床 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 | 轻量级地图库,自定义性强 |