# 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 事件)
