# AGENTS.md - haha-admin-web 智能体代码生成规则 > 本文件为 AI Agent 代码生成提供强制规则约束,定义生成边界与规范。 > 所有规则均为强制性,Agent 生成代码时必须严格遵守。违反规则的代码不可提交。 --- ## 1. 项目边界 ### 1.1 技术栈版本锁定 | 技术 | 版本 | 禁止事项 | |------|------|----------| | Node.js | ^20.19.0 \|\| >=22.13.0 | 禁止使用 Node 18 及以下 | | pnpm | >=9 | 禁止使用 npm/yarn | | Vue | ^3.5.25 | Composition API only,禁止 Options API | | TypeScript | ^5.9.3 | 禁止 any 滥用,新代码必须提供类型 | | Vite | ^7.2.7 | -- | | Element Plus | ^2.12.0 | 禁止引入 Ant Design / Naive UI 等其他组件库 | | Pinia | ^3.0.4 | 禁止 Vuex | | Vue Router | ^4.6.3 | -- | | Tailwind CSS | ^4.1.17 | 用于工具类,禁止替代组件级样式 | | ECharts | ^6.0.0 | 图表统一使用 ECharts | | Axios | ^1.13.2 | HTTP 请求统一使用 `http` 实例,禁止直接 `axios` | | dayjs | ^1.11.19 | 禁止引入 moment.js | | Sass | ^1.95.1 | 样式预处理统一使用 SCSS | ### 1.2 后端 API 对接 | 配置项 | 值 | |--------|-----| | 后端服务地址 | `http://localhost:7070/admin` | | 开发端口 | 8888 | | API 代理 | vite.config.ts 中 `apiPaths` 动态生成 | | 生产 publicPath | `/admin/` | | 路由模式 | hash | ### 1.3 目录职责(严格遵循) ``` src/ ├── api/ # API 请求函数(每个模块一个文件) ├── assets/ # 静态资源(图标、图片、字体) ├── components/ # 全局公共组件(ReXxx 命名) ├── config/ # 应用配置 ├── directives/ # 自定义指令 ├── layout/ # 布局框架 ├── plugins/ # 插件注册(ElementPlus、I18n、ECharts、VxeTable) ├── router/ # 路由配置(modules/ 下按模块拆分) ├── store/ # Pinia 状态管理(modules/ 下按模块拆分) ├── style/ # 全局样式(reset、index、tailwind、element-plus、dark) ├── utils/ # 工具函数 ├── views/ # 页面视图(每个模块一个目录) │ └── {module}/ │ ├── index.vue # 页面入口 │ └── utils/ │ ├── hook.tsx # 业务逻辑 hook(composable) │ └── types.ts # 模块类型定义 └── main.ts # 应用入口 ``` --- ## 2. 代码生成规则 ### 2.1 页面视图 (views) **强制结构**:每个业务页面必须按以下模式组织: ``` views/{module}/ ├── index.vue # 纯模板 + 结构,不含业务逻辑 └── utils/ ├── hook.tsx # 业务逻辑 composable(export function useXxx) └── types.ts # 模块内类型定义 ``` **index.vue 模板**: ```vue ``` **hook.tsx 模板**: ```tsx import { ref, reactive, onMounted } from "vue"; import type { PaginationProps } from "@pureadmin/table"; import { message } from "@/utils/message"; import { getXxxList } from "@/api/xxx"; import type { XxxItem, XxxSearchForm } from "./types"; export function useXxx(tableRef: Ref) { const form = reactive({ /* 初始值 */ }); const dataList = ref([]); const loading = ref(true); const pagination = reactive({ total: 0, pageSize: 10, currentPage: 1, background: true }); const columns: TableColumnList = [ { label: "xxx", prop: "xxx", minWidth: 120 }, // ... ]; const onSearch = async () => { loading.value = true; try { const { data } = await getXxxList({ ...form, page: pagination.currentPage, pageSize: pagination.pageSize }); dataList.value = data.list; pagination.total = data.total; } finally { loading.value = false; } }; const resetForm = (formEl: any) => { if (!formEl) return; formEl.resetFields(); onSearch(); }; const handleSizeChange = (val: number) => { pagination.pageSize = val; onSearch(); }; const handleCurrentChange = (val: number) => { pagination.currentPage = val; onSearch(); }; onMounted(() => { onSearch(); }); return { form, loading, columns, dataList, pagination, onSearch, resetForm, handleSizeChange, handleCurrentChange }; } ``` **types.ts 模板**: ```ts export interface XxxItem { id: number; // 字段定义 } export interface XxxSearchForm { // 搜索表单字段 } ``` ### 2.2 API 层 (api/) **强制规则**: 1. 每个 API 文件对应一个后端模块,文件名与后端路径一致 2. 统一使用 `http.request(method, url, config)` 调用 3. 必须定义 `Result` 和 `ResultTable` 类型(可复用已有定义) **API 文件模板**: ```ts import { http } from "@/utils/http"; type Result = { code: number; message: string; data?: any; }; type ResultTable = { code: number; message: string; data?: { list: Array; total: number; pageSize: number; currentPage: number; }; }; // 列表查询 export const getXxxList = (params: { page?: number; pageSize?: number; // ...搜索参数 }) => { return http.request("get", "/xxx/list", { params }); }; // 详情查询 export const getXxxById = (id: number) => { return http.request("get", `/xxx/${id}`); }; // 新增 export const createXxx = (data: any) => { return http.request("post", "/xxx", { data }); }; // 修改状态 export const updateXxxStatus = (id: number, status: number) => { return http.request("put", `/xxx/${id}/status?status=${status}`); }; // 删除 export const deleteXxx = (id: number) => { return http.request("delete", `/xxx/${id}`); }; ``` **禁止事项**: - 禁止直接 `import axios` 调用,必须使用 `http` 实例 - 禁止在 API 函数中处理 UI 逻辑(如 ElMessage) - 禁止硬编码后端地址 ### 2.3 路由 (router/modules/) **路由文件模板**: ```ts export default { path: "/xxx", redirect: "/xxx/list", meta: { icon: "ri:xxx-line", // Remix Icon title: "xxx管理", rank: 数字 // 菜单排序 }, children: [ { path: "/xxx/list", name: "XxxList", // PascalCase component: () => import("@/views/xxx/index.vue"), meta: { icon: "ri:xxx-line", title: "xxx管理" } } ] } satisfies RouteConfigsTable; ``` **强制规则**: - 路由 path 使用 kebab-case - 路由 name 使用 PascalCase - 图标统一使用 Remix Icon(`ri:xxx-line`) - 懒加载必须用 `() => import()` 语法 ### 2.4 Store (store/modules/) **Store 模板**: ```ts import { defineStore } from "pinia"; import { store } from "../utils"; export const useXxxStore = defineStore("pure-xxx", { state: (): XxxState => ({ // 状态 }), actions: { // 方法命名:SET_XXX (修改状态)、async方法 (异步操作) } }); export function useXxxStoreHook() { return useXxxStore(store); } ``` **强制规则**: - Store ID 前缀 `pure-` - 必须导出 `useXxxStoreHook` 辅助函数 - 状态修改方法以 `SET_` 前缀命名 ### 2.5 组件 (components/) **强制规则**: - 全局公共组件以 `Re` 前缀命名(如 `ReDialog`、`ReIcon`) - 组件导出使用 `index.ts` 桶文件 - 禁止在公共组件中写入业务逻辑 --- ## 3. 样式规则 ### 3.1 样式方案 | 场景 | 方案 | 说明 | |------|------|------| | 布局与间距 | Tailwind CSS | `w-full`、`pl-8`、`pt-[12px]` 等 | | 组件级样式 | `