159 lines
5.8 KiB
Markdown
159 lines
5.8 KiB
Markdown
# juip-web - AI 开发助手指南
|
||
|
||
## 项目概述
|
||
|
||
Vite + React 19 纯 SPA 代理服务站点,包含公开营销页与用户管理后台。使用 Bun 运行时、react-router-dom 7 路由、Tailwind CSS 4、shadcn/ui (radix-nova 风格)、sonner 提示、biome 代码规范。
|
||
|
||
**核心业务**: IP 代理产品展示与购买、订单支付、短信验证码注册登录、后台资源/通道/白名单管理
|
||
|
||
## 架构模式
|
||
|
||
### 三层数据流架构
|
||
|
||
1. **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`
|
||
|
||
2. **会话状态** (`src/api/token.ts`) - 令牌存取唯一入口
|
||
- 登录后 token/userInfo 由后端 Set-Cookie 下发,经 `apiLogin` 镜像到 localStorage
|
||
- `setSession()` / `clearSession()` 统一派发 `auth-change` 事件驱动 UI 重渲染
|
||
- UI 组件 (header/authGuard) 通过 `isAuthed()` 读取登录态,禁止直接读 localStorage
|
||
- 401 时 user 模式自动 `clearSession()`,device 模式自动清缓存重取设备令牌
|
||
|
||
3. **UI 层** - 业务域 API 函数供组件直接调用
|
||
- 公开页组件位于 `src/home/*`,后台位于 `src/admin/*`
|
||
- `/admin` 路由由 `AuthGuard` 保护,未登录重定向 `/login?redirect=`
|
||
|
||
### API 层使用示例
|
||
|
||
```typescript
|
||
// 业务域文件: 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)
|
||
}
|
||
```
|
||
|
||
### 组件调用示例
|
||
|
||
```typescript
|
||
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`。
|
||
|
||
## 开发工作流
|
||
|
||
### 命令速查
|
||
|
||
```bash
|
||
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](src/api/base.ts) - API 调用核心 (三模式 + Code 信封适配 + GET 去重 + 设备令牌缓存)
|
||
- [src/api/token.ts](src/api/token.ts) - 会话状态存取与 auth-change 事件
|
||
- [src/api/auth.ts](src/api/auth.ts) - 登录/注册/退出业务域
|
||
- [src/lib/api.ts](src/lib/api.ts) - ApiResponse 类型与后端配置
|
||
- [src/routers/index.tsx](src/routers/index.tsx) - 全部路由定义
|
||
- [src/components/authGuard.tsx](src/components/authGuard.tsx) - 后台路由守卫
|
||
- [src/home/header.tsx](src/home/header.tsx) - 登录态响应式更新 (auth-change/focus 事件)
|