5.8 KiB
5.8 KiB
juip-web - AI 开发助手指南
项目概述
Vite + React 19 纯 SPA 代理服务站点,包含公开营销页与用户管理后台。使用 Bun 运行时、react-router-dom 7 路由、Tailwind CSS 4、shadcn/ui (radix-nova 风格)、sonner 提示、biome 代码规范。
核心业务: IP 代理产品展示与购买、订单支付、短信验证码注册登录、后台资源/通道/白名单管理
架构模式
三层数据流架构
-
API 层 (
src/api/*.ts) - 所有后端调用统一入口- 每个文件对应一个业务域 (auth, order, product, verify, captcha)
- 通过
base.ts的三种调用模式访问后端:callPublic()- 无需认证的公开接口callByDevice()- 使用 CLIENT_ID/CLIENT_SECRET 的设备级认证callByUser()- 使用用户会话 token 的用户级认证
- 所有调用返回统一的
ApiResponse<T>类型 - 后端存在两套响应约定,
base.ts自动识别:- 裸 JSON (OAuth2 接口、
/script/linedata/*.php等) - 原样返回 - 会员接口信封
{Code, Message, Data}- 顶层有Code字段时自动解包:Code === 10000成功返回Data/data,否则转success: false+Message
- 裸 JSON (OAuth2 接口、
-
会话状态 (
src/api/token.ts) - 令牌存取唯一入口- 登录后 token/userInfo 由后端 Set-Cookie 下发,经
apiLogin镜像到 localStorage setSession()/clearSession()统一派发auth-change事件驱动 UI 重渲染- UI 组件 (header/authGuard) 通过
isAuthed()读取登录态,禁止直接读 localStorage - 401 时 user 模式自动
clearSession(),device 模式自动清缓存重取设备令牌
- 登录后 token/userInfo 由后端 Set-Cookie 下发,经
-
UI 层 - 业务域 API 函数供组件直接调用
- 公开页组件位于
src/home/*,后台位于src/admin/* /admin路由由AuthGuard保护,未登录重定向/login?redirect=
- 公开页组件位于
API 层使用示例
// 业务域文件: src/api/xxx.ts
import type { ApiResponse } from "@/lib/api"
import { callByUser, callPublic } from "./base"
// 1. 公开接口 (GET 自动并发去重)
const resp = await callPublic<{ token: string; base64: string }>(
"/api/captcha/get",
undefined,
"GET",
)
// 2. 设备级认证 (client_credentials 令牌模块内单飞缓存,提前 60s 过期)
const resp2 = await callByDevice<{ access_token: string }>(
"/api/auth/token",
{ grant_type: "client_credentials" },
)
// 3. 用户级认证 (读取会话 token,401 自动清会话)
const resp3 = await callByUser<CreateOrderData>("/product/CreateOrder", data)
const resp4 = await callByUser<number>(
`/product/IsPay?orderNo=${orderNo}`,
undefined,
"GET",
)
// 4. Code 信封接口 (顶层有 Code 字段自动解包,Code === 10000 成功)
const resp5 = await callPublic("/user/ApiLogin", {
Logincode: "xxx",
Password: "xxx",
})
const resp6 = await callPublic<ProductItem[]>(
"/product/ApiProductActive",
undefined,
"GET",
)
// 5. 统一响应处理
if (resp.success) {
console.log(resp.data) // 强类型 T
} else {
console.error(resp.status, resp.message)
}
组件调用示例
import { fetchProducts } from "@/api/product"
import { toast } from "sonner"
const result = await fetchProducts()
if (result.success) {
setProducts(result.data)
} else {
toast.error(result.message)
}
路由组织
/- 公开站点 (LayoutPage 统一头部/底部): 首页、/product(+/buy//http//routeros)、/ipline、/softdownload、/help、/client/login- 登录/注册 (tab 状态经location.state.tab切换)/admin- 用户后台 (AuthGuard 保护): dashboard、channels、whitelist、funds、product/long、product/short
路由定义集中在 src/routers/index.tsx。
开发工作流
命令速查
bun install # 安装依赖
bun dev # 开发服务器 (vite --host)
bun run build # 生产构建 (tsc -b && vite build)
bun run lint # biome 检查并自动修复
代码规范 (biome)
- 无分号、双引号、2 空格缩进、单参数箭头函数省略括号
- import 自动排序 (organizeImports)
noNonNullAssertion为 error,禁用!断言- 提交前运行
bun run lint
组件开发模式
shadcn/ui 组件 (src/components/ui/*.tsx)
- 通过 CLI 添加:
bunx shadcn@latest add <component> - 类名合并使用
cn()(来自@/lib/utils)
业务组件
src/components/composites/*- 复杂对话框等src/components/*- 通用组件 (wrap 布局容器、authGuard 路由守卫、data-table、page)
表单: react-hook-form + zod 校验
提示: 统一使用 sonner (toast.success / toast.error)
项目特定约定
类型定义
- 后端响应统一为
ApiResponse<T>(定义于src/lib/api.ts):- 成功:
{success: true, data: T} - 失败:
{success: false, status?: number, message: string}
- 成功:
- 请求/响应业务类型定义在对应业务域 API 文件中 (如
src/api/order.ts的CreateOrderRequest) - UI 展示模型位于
src/lib/models/*
环境变量 (见 .env)
VITE_API_BASE_URL- 后端地址 (留空表示同源,登录 Cookie 自动携带)VITE_CLIENT_ID/VITE_CLIENT_SECRET- OAuth2 设备认证凭据 (当前均为web)
关键文件参考
- src/api/base.ts - API 调用核心 (三模式 + Code 信封适配 + GET 去重 + 设备令牌缓存)
- src/api/token.ts - 会话状态存取与 auth-change 事件
- src/api/auth.ts - 登录/注册/退出业务域
- src/lib/api.ts - ApiResponse 类型与后端配置
- src/routers/index.tsx - 全部路由定义
- src/components/authGuard.tsx - 后台路由守卫
- src/home/header.tsx - 登录态响应式更新 (auth-change/focus 事件)