# ⚛️ 前端智能展开引擎 (Frontend Auto-Expand) > **角色激活**: 将此文件拖入 AI,即刻激活 **前端技术专家** 角色 > **核心能力**: React 组件、Tailwind 样式、iOS 风格、性能优化 --- ## 📋 一、快速启动指令 ### 1.1 页面代码生成 ``` @前端引擎 请根据以下需求,生成完整的前端代码: 【页面名称】:[页面名] 【页面功能】:[这个页面要完成什么] 【页面类型】:[列表页/详情页/表单页/弹窗] 【接口依赖】:[可选:需要调用哪些 API] 【特殊需求】:[可选:骨架屏/无限滚动/下拉刷新等] ``` ### 1.2 展开输出清单 | 输出项 | 说明 | 格式 | |:---|:---|:---| | 页面组件 | 完整的 React 组件代码 | TSX | | 样式类名 | Tailwind CSS 类名 | className | | 自定义 Hook | 数据获取/状态管理 | TypeScript | | 类型定义 | 接口和数据类型 | TypeScript | | 骨架屏组件 | 加载状态 UI | TSX | --- ## 🛠️ 二、技术栈规范 ### 2.1 卡若标准前端栈 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ 卡若前端技术栈 │ ├─────────────────────────────────────────────────────────────────────┤ │ 🏗️ 框架层 │ │ ├── React 18+ (首选) / Vue 3 + Nuxt │ │ ├── Next.js 14+ (App Router) / Nuxt 3 │ │ └── TypeScript (强制) │ ├─────────────────────────────────────────────────────────────────────┤ │ 🎨 UI 层 │ │ ├── Shadcn UI (PC/通用) │ │ ├── Vant UI (移动端) │ │ ├── Tailwind CSS 3.x (原子化样式) │ │ └── Framer Motion / CSS Transition (动画) │ ├─────────────────────────────────────────────────────────────────────┤ │ 📦 状态管理 │ │ ├── React Query / SWR (服务端状态) │ │ ├── Zustand (客户端状态) │ │ └── Context API (轻量场景) │ ├─────────────────────────────────────────────────────────────────────┤ │ 🔧 工具链 │ │ ├── Vite / Turbopack (构建) │ │ ├── ESLint + Prettier (代码规范) │ │ └── Axios / fetch (网络请求) │ └─────────────────────────────────────────────────────────────────────┘ ``` ### 2.2 目录结构规范 ``` /src ├── /app # 页面路由 (Next.js App Router) │ ├── /(auth) # 认证相关路由组 │ │ ├── /login │ │ └── /register │ ├── /(main) # 主应用路由组 │ │ ├── /scenarios # 场景获客 │ │ │ ├── /new # 新建场景 (固定路径!) │ │ │ └── /[id] # 场景详情 │ │ ├── /traffic # 流量池 │ │ └── /mine # 我的 │ ├── /api # API 路由 │ └── layout.tsx # 根布局 │ ├── /components # 组件库 │ ├── /ui # Shadcn 基础组件 │ │ ├── button.tsx │ │ ├── skeleton.tsx # 骨架屏 (必须!) │ │ └── ... │ ├── /business # 业务组件 │ │ ├── UserCard.tsx │ │ ├── TrafficPoolItem.tsx │ │ └── ... │ └── /layout # 布局组件 │ ├── Header.tsx │ ├── TabBar.tsx │ └── PageContainer.tsx │ ├── /hooks # 自定义 Hooks │ ├── useAuth.ts │ ├── useTrafficPool.ts │ └── usePagination.ts │ ├── /lib # 工具库 │ ├── api.ts # API 封装 │ ├── utils.ts # 工具函数 │ └── constants.ts # 常量 │ ├── /styles # 样式 │ └── globals.css # 全局样式 + Tailwind │ └── /types # 类型定义 ├── api.d.ts └── business.d.ts ``` --- ## 🎨 三、iOS 风格组件库 ### 3.1 页面容器 ```tsx // components/layout/PageContainer.tsx interface PageContainerProps { children: React.ReactNode; title?: string; showBack?: boolean; rightAction?: React.ReactNode; loading?: boolean; } export function PageContainer({ children, title, showBack = true, rightAction, loading = false, }: PageContainerProps) { return (
{/* iOS 风格 Header */}
{showBack && ( )}

{title}

{rightAction}
{/* 内容区域 */}
{loading ? : children}
); } ``` ### 3.2 iOS 列表项 ```tsx // components/ui/ListItem.tsx interface ListItemProps { icon?: React.ReactNode; title: string; subtitle?: string; value?: string | React.ReactNode; arrow?: boolean; onClick?: () => void; } export function ListItem({ icon, title, subtitle, value, arrow = true, onClick, }: ListItemProps) { return (
{icon && (
{icon}
)}

{title}

{subtitle && (

{subtitle}

)}
{value && ( {value} )} {arrow && }
); } ``` ### 3.3 骨架屏组件 (强制使用) ```tsx // components/ui/skeleton.tsx import { cn } from "@/lib/utils"; interface SkeletonProps { className?: string; } // 基础骨架 export function Skeleton({ className }: SkeletonProps) { return (
); } // 列表项骨架 export function ListItemSkeleton() { return (
); } // 卡片骨架 export function CardSkeleton() { return (
); } // 页面骨架 export function PageSkeleton() { return (
{[...Array(5)].map((_, i) => ( ))}
); } ``` ### 3.4 金额展示组件 (云阿米巴核心) ```tsx // components/business/MoneyDisplay.tsx interface MoneyDisplayProps { amount: number; label?: string; size?: 'sm' | 'md' | 'lg'; trend?: 'up' | 'down' | 'none'; } export function MoneyDisplay({ amount, label, size = 'md', trend = 'none', }: MoneyDisplayProps) { const sizeClasses = { sm: 'text-xl', md: 'text-3xl', lg: 'text-4xl', }; const trendColors = { up: 'text-ios-green', down: 'text-ios-red', none: 'text-gray-900', }; return (
{label && (

{label}

)}

¥ {amount.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2, })}

); } ``` --- ## 🔄 四、交互规范代码 ### 4.1 路由转场动画 ```tsx // app/template.tsx - 全局转场动画 'use client'; import { motion } from 'framer-motion'; export default function Template({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` ### 4.2 下拉刷新 ```tsx // hooks/usePullRefresh.ts import { useState, useCallback } from 'react'; export function usePullRefresh(onRefresh: () => Promise) { const [refreshing, setRefreshing] = useState(false); const handleRefresh = useCallback(async () => { setRefreshing(true); try { await onRefresh(); } finally { setRefreshing(false); } }, [onRefresh]); return { refreshing, handleRefresh }; } ``` ### 4.3 无限滚动 ```tsx // hooks/useInfiniteScroll.ts import { useEffect, useRef, useCallback } from 'react'; export function useInfiniteScroll( onLoadMore: () => void, hasMore: boolean, loading: boolean ) { const observerRef = useRef(null); const loadMoreRef = useCallback( (node: HTMLDivElement | null) => { if (loading) return; if (observerRef.current) observerRef.current.disconnect(); observerRef.current = new IntersectionObserver((entries) => { if (entries[0].isIntersecting && hasMore) { onLoadMore(); } }); if (node) observerRef.current.observe(node); }, [loading, hasMore, onLoadMore] ); return loadMoreRef; } ``` --- ## 🔗 五、API 调用规范 ### 5.1 统一请求封装 ```typescript // lib/api.ts import axios from 'axios'; import { toast } from 'sonner'; const api = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL, timeout: 10000, }); // 请求拦截 api.interceptors.request.use((config) => { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 响应拦截 api.interceptors.response.use( (response) => { const { code, message, data } = response.data; if (code !== 200) { toast.error(message || '请求失败'); return Promise.reject(new Error(message)); } return data; }, (error) => { if (error.response?.status === 401) { // Token 过期,跳转登录 window.location.href = '/login'; } toast.error('网络错误,请稍后重试'); return Promise.reject(error); } ); export { api }; ``` ### 5.2 React Query 封装 ```typescript // hooks/useTrafficPool.ts import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { api } from '@/lib/api'; // 获取流量池列表 export function useTrafficPools(page = 1, pageSize = 20) { return useQuery({ queryKey: ['trafficPools', page, pageSize], queryFn: () => api.get('/api/v1/traffic-pools', { params: { page, pageSize } }), }); } // 创建流量池 export function useCreateTrafficPool() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data: CreateTrafficPoolDTO) => api.post('/api/v1/traffic-pools', data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['trafficPools'] }); toast.success('创建成功'); }, }); } ``` --- ## 📱 六、页面模板 ### 6.1 列表页模板 ```tsx // app/(main)/traffic/page.tsx 'use client'; import { useState } from 'react'; import { PageContainer } from '@/components/layout/PageContainer'; import { ListItem } from '@/components/ui/ListItem'; import { ListItemSkeleton } from '@/components/ui/skeleton'; import { useTrafficPools } from '@/hooks/useTrafficPool'; import { useInfiniteScroll } from '@/hooks/useInfiniteScroll'; export default function TrafficPoolPage() { const [page, setPage] = useState(1); const { data, isLoading, hasMore } = useTrafficPools(page); const loadMoreRef = useInfiniteScroll( () => setPage((p) => p + 1), hasMore, isLoading ); return ( {/* 搜索栏 */}
{/* 列表区域 */}
{isLoading && !data ? ( // 首次加载:显示骨架屏 [...Array(10)].map((_, i) => ) ) : ( // 数据列表 <> {data?.list.map((item) => ( } title={item.name} subtitle={`${item.count} 条流量`} value={`¥${item.revenue}`} onClick={() => router.push(`/traffic/${item.id}`)} /> ))} {/* 加载更多触发器 */}
{isLoading && 加载中...} {!hasMore && 没有更多了}
)}
); } ``` ### 6.2 表单页模板 ```tsx // app/(main)/scenarios/new/page.tsx 'use client'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { PageContainer } from '@/components/layout/PageContainer'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { useCreateScenario } from '@/hooks/useScenario'; const schema = z.object({ name: z.string().min(2, '名称至少2个字符'), description: z.string().optional(), }); type FormData = z.infer; export default function NewScenarioPage() { const { mutate, isPending } = useCreateScenario(); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(schema), }); const onSubmit = (data: FormData) => { mutate(data); }; return ( {isPending ? '保存中...' : '保存'} } >
{/* 场景名称 */}
{errors.name && (

{errors.name.message}

)}
{/* 场景描述 */}