From 4235458bea1a0f2ee9fca4aebde168785a936d82 Mon Sep 17 00:00:00 2001 From: Eamon <17516219072@163.com> Date: Thu, 13 Aug 2026 18:28:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=99=BB=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 2 +- .github/copilot-instructions.md | 158 ++++ src/App.tsx | 8 +- src/admin/clients.tsx | 13 +- src/admin/nav-menu.tsx | 112 +-- src/api/auth.ts | 144 ++-- src/api/base.ts | 228 +++--- src/{lib/cap/index.ts => api/captcha.ts} | 6 +- src/api/order.ts | 64 ++ src/api/product.ts | 11 + src/api/token.ts | 39 + src/api/verify.ts | 9 +- src/components/authGuard.tsx | 53 +- src/components/productDropdown.tsx | 184 +++++ src/components/profileOrLogin.tsx | 69 ++ src/components/ui/radio-group.tsx | 4 +- src/home/header.tsx | 175 +---- src/home/login/index.tsx | 41 +- src/home/product/buy.tsx | 935 +++++++++++++++++++++++ src/home/product/index.tsx | 91 ++- src/home/product/productGrid.tsx | 4 + src/lib/api.ts | 35 +- src/lib/models/product.ts | 372 +++------ src/routers/index.tsx | 2 + vite.config.ts | 14 + 25 files changed, 1900 insertions(+), 873 deletions(-) create mode 100644 .github/copilot-instructions.md rename src/{lib/cap/index.ts => api/captcha.ts} (51%) create mode 100644 src/api/order.ts create mode 100644 src/api/product.ts create mode 100644 src/api/token.ts create mode 100644 src/components/productDropdown.tsx create mode 100644 src/components/profileOrLogin.tsx create mode 100644 src/home/product/buy.tsx diff --git a/.env b/.env index 9746e73..1ac56d4 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -VITE_API_BASE_URL=http://192.168.3.42:8080 +VITE_API_BASE_URL= VITE_CLIENT_ID=web VITE_CLIENT_SECRET=web \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..d83a7e1 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,158 @@ +# 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` 类型 + - 后端存在两套响应约定,`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("/product/CreateOrder", data) +const resp4 = await callByUser( + `/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( + "/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 ` +- 类名合并使用 `cn()` (来自 `@/lib/utils`) + +**业务组件** +- `src/components/composites/*` - 复杂对话框等 +- `src/components/*` - 通用组件 (wrap 布局容器、authGuard 路由守卫、data-table、page) + +**表单**: react-hook-form + zod 校验 + +**提示**: 统一使用 sonner (`toast.success / toast.error`) + +## 项目特定约定 + +### 类型定义 + +- 后端响应统一为 `ApiResponse` (定义于 `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 事件) diff --git a/src/App.tsx b/src/App.tsx index 61901c5..27c9932 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,14 @@ import { RouterProvider } from "react-router-dom" +import { Toaster } from "@/components/ui/sonner" import { router } from "./routers" function App() { - return + return ( + <> + + + + ) } export default App diff --git a/src/admin/clients.tsx b/src/admin/clients.tsx index 1083f26..29838fd 100644 --- a/src/admin/clients.tsx +++ b/src/admin/clients.tsx @@ -17,6 +17,7 @@ import { } from "lucide-react" import { type ReactNode, useState } from "react" import { Link } from "react-router-dom" +import ProfileOrLogin from "@/components/profileOrLogin" import { Button } from "@/components/ui/button" import { Tooltip, @@ -100,22 +101,12 @@ export function Header() {
- {/* - 返回首页 - */} - +
) } -function UserCenter() { - return
用户
-} - export function Navbar() { const { navbar } = useLayout() diff --git a/src/admin/nav-menu.tsx b/src/admin/nav-menu.tsx index ec0644a..7ed9432 100644 --- a/src/admin/nav-menu.tsx +++ b/src/admin/nav-menu.tsx @@ -1,6 +1,7 @@ import { useCallback, useRef, useState } from "react" import { createPortal } from "react-dom" -import { NavLink, useNavigate } from "react-router-dom" +import { NavLink } from "react-router-dom" +import ProductDropdown from "@/components/productDropdown" import { cn } from "@/lib/utils" export function AdminNavMenu() { @@ -8,7 +9,7 @@ export function AdminNavMenu() {