From 2fcfece32b092b9e6e37930f47831928891ebbcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B9=9B=E5=85=AE?= Date: Tue, 26 May 2026 11:30:03 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E5=AE=8C=E5=96=84=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E8=AF=B4=E6=98=8E=E5=92=8C=E5=8D=8F=E4=BD=9C=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .codex/skills/readme-structure-sync/SKILL.md | 20 ++++ AGENTS.md | 1 + README.en-US.md | 109 +++++++++++++++---- README.md | 103 ++++++++++++++++-- RTK.md | 20 ++++ src/api/access.ts | 13 +++ src/layout/types.ts | 6 + src/router/modules/employees.ts | 6 + src/router/modules/home.ts | 6 + src/views/employees/index.vue | 7 ++ src/views/roles/index.vue | 5 + src/views/stores/index.vue | 4 + 12 files changed, 270 insertions(+), 30 deletions(-) create mode 100644 .codex/skills/readme-structure-sync/SKILL.md create mode 100644 AGENTS.md create mode 100644 RTK.md diff --git a/.codex/skills/readme-structure-sync/SKILL.md b/.codex/skills/readme-structure-sync/SKILL.md new file mode 100644 index 0000000..24c2c70 --- /dev/null +++ b/.codex/skills/readme-structure-sync/SKILL.md @@ -0,0 +1,20 @@ +--- +name: readme-structure-sync +description: Use this skill when changing files, folders, package scripts, routes, API modules, or project conventions in role-admin; it ensures README.md stays synchronized with the current repository structure. +--- + +# README Structure Sync + +Use this skill whenever a task changes repository structure, important entry files, package scripts, routes, API modules, environment variables, or collaboration conventions. + +## Workflow + +1. Inspect the touched files and decide whether they affect `README.md`. +2. If directories or key files were added, removed, renamed, or moved, update the `README.md` directory map. +3. If `package.json` scripts changed, update the `README.md` important scripts table. +4. If business modules, API contracts, routes, or environment variables changed, update the matching README section. +5. Keep README descriptions short and operational: what the file or directory does, not a generic framework explanation. + +## Touch-Up Rule + +Do not scan the whole repository only for this skill. When a task already touches applicable files, fix obvious README drift in the same pass. If full cleanup is larger than the request, update the current workflow and top-level declarations, then call out the remaining gap. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..351259c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +@RTK.md diff --git a/README.en-US.md b/README.en-US.md index 104b8d5..be8ef1d 100644 --- a/README.en-US.md +++ b/README.en-US.md @@ -1,39 +1,106 @@ -

vue-pure-admin Lite Edition(no i18n version)

- -[![license](https://img.shields.io/github/license/pure-admin/vue-pure-admin.svg)](LICENSE) +# role-admin **English** | [中文](./README.md) -## Introduce +Store employee access-management admin UI, based on the `pure-admin-thin` template and customized for store, role, and employee CRUD workflows. -The simplified version is based on the shelf extracted from [vue-pure-admin](https://github.com/pure-admin/vue-pure-admin), which contains main functions and is more suitable for actual project development. The packaged size is introduced globally [element-plus](https://element-plus.org) is still below `2.3MB`, and the full version of the code will be permanently synchronized. After enabling `brotli` compression and `cdn` to replace the local library mode, the package size is less than `350kb` +## Stack -## Supporting video +- `Vue 3` + `TypeScript` +- `Vite` +- `Element Plus` +- `Pinia` +- `Vue Router` +- `Axios` -[Click me to view UI design](https://www.bilibili.com/video/BV17g411T7rq) -[Click me to view the rapid development tutorial](https://www.bilibili.com/video/BV1kg411v7QT) +## Requirements -## Nanny-level documents +- `Node.js`: `^20.19.0 || >=22.13.0` +- `pnpm`: `>=9` +- Local backend: `/Users/mac033/Desktop/my-project/access-manage` -[Click me to view vue-pure-admin documentation](https://pure-admin.cn/) -[Click me to view @pureadmin/utils documentation](https://pure-admin-utils.netlify.app) +## Local Development -## Premium service +Start the backend first: -[Click me to view details](https://pure-admin.cn/pages/service/) +```bash +cd /Users/mac033/Desktop/my-project/access-manage +pnpm mysql:up +pnpm db:migrate +pnpm dev +``` -## Preview +Then start this admin UI: -[Click me to view the preview station](https://pure-admin-thin.netlify.app/#/login) +```bash +cd /Users/mac033/Desktop/my-project/role-admin +pnpm install +pnpm dev +``` -## Maintainer +Open: -[xiaoxian521](https://github.com/xiaoxian521) +```text +http://localhost:8848/ +``` -## ⚠️ Attention +## Project Structure -The Lite version does not accept any issues and prs. If you have any questions, please go to the full version [issues](https://github.com/pure-admin/vue-pure-admin/issues/new/choose) to mention, thank you! +```text +. +├── .codex/skills/ # Repository-local skill for keeping README.md in sync +├── .husky/ # Git hooks for lint-staged and commitlint +├── build/ # Vite plugin, CDN, compression, and build helpers +├── mock/ # Template mock data for login and async routes +├── public/ # Static assets and runtime platform config +├── src/ +│ ├── api/ # HTTP API wrappers; business APIs live in access.ts +│ ├── assets/ # Images, SVG files, and iconfont assets +│ ├── components/ # Shared template components +│ ├── config/ # Runtime config loader +│ ├── directives/ # Custom Vue directives +│ ├── layout/ # Admin layout, menu, tabs, navbar, and hooks +│ ├── plugins/ # Plugin registration +│ ├── router/ # Static routes, remaining routes, router instance, guards +│ ├── store/ # Pinia stores +│ ├── style/ # Global styles and themes +│ ├── utils/ # Auth, HTTP, storage, message, progress, and tree helpers +│ └── views/ # Pages; business pages live in employees, roles, stores +├── types/ # Global TypeScript declarations +├── AGENTS.md # Agent entrypoint that delegates to RTK.md +├── RTK.md # Repository collaboration rules +├── package.json # Dependencies, scripts, engines, and pnpm guard +└── vite.config.ts # Vite dev proxy, plugins, and build output config +``` -## License +This repository is not a monorepo and has no `packages/` directory. Important scripts are defined in `package.json`. -[MIT © 2020-present, pure-admin](./LICENSE) +## Important Scripts + +| Script | Purpose | +| -------------------- | -------------------------------------------------- | +| `pnpm dev` | Start the Vite dev server on the configured port | +| `pnpm build` | Clean `dist` and build for production | +| `pnpm build:staging` | Build with staging mode | +| `pnpm report` | Build and open a Rollup visualizer report | +| `pnpm preview` | Preview an existing `dist` build | +| `pnpm preview:build` | Build first, then preview | +| `pnpm typecheck` | Run TypeScript and Vue type checks | +| `pnpm lint` | Run ESLint, Prettier, and Stylelint fixes | +| `pnpm svgo` | Compress SVG files recursively | +| `pnpm clean:cache` | Reinstall dependencies after clearing local caches | + +## Backend Proxy + +Development mode proxies `/api` to `VITE_API_PROXY_TARGET`, defaulting to `http://localhost:3500`. The relevant files are `.env.development` and `vite.config.ts`. + +## Documentation Sync Rule + +When files, folders, package scripts, API modules, route modules, or key config files change, update `README.md` in the same change. The local skill is stored at `.codex/skills/readme-structure-sync/SKILL.md`. + +## Verification + +```bash +pnpm typecheck +pnpm build +``` diff --git a/README.md b/README.md index 0613642..93eda86 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,22 @@ # role-admin -门店员工权限管理后台,基于 `pure-admin-thin` 精简模板二次开发。 +门店员工权限管理后台,基于 `pure-admin-thin` 精简模板二次开发。当前业务聚焦门店、角色、员工三类基础数据管理,并通过 Vite 代理对接本地 `access-manage` 后端服务。 ## 技术栈 -- Vue 3 -- Vite -- TypeScript -- Element Plus -- Pinia -- Vue Router -- Axios +- `Vue 3` + `TypeScript` +- `Vite` +- `Element Plus` +- `Pinia` +- `Vue Router` +- `Axios` +- `@pureadmin/table` / `@pureadmin/utils` + +## 环境要求 + +- `Node.js`: `^20.19.0 || >=22.13.0` +- `pnpm`: `>=9` +- 本地后端:`/Users/mac033/Desktop/my-project/access-manage` ## 本地启动 @@ -37,9 +43,71 @@ pnpm dev http://localhost:8848/ ``` +## 目录说明 + +```text +. +├── .codex/skills/ # 仓库内协作 skill,约束结构变更后同步 README +├── .husky/ # Git hooks,提交前执行 lint-staged,提交信息走 commitlint +├── .vscode/ # VS Code 推荐配置与 Vue 代码片段 +├── build/ # Vite 插件、CDN、压缩、构建信息与工具函数 +├── mock/ # pure-admin 模板保留的 mock 登录/路由数据 +├── public/ # 静态资源与运行时平台配置 +├── src/ # 前端源码 +│ ├── api/ # HTTP API 封装,业务接口集中在 access.ts +│ ├── assets/ # 图片、SVG、iconfont 等静态资源 +│ ├── components/ # 模板沉淀的通用组件 +│ ├── config/ # 读取 public/platform-config.json 的运行时配置 +│ ├── directives/ # 自定义指令,如权限、复制、长按、波纹 +│ ├── layout/ # 后台布局、菜单、标签页、导航栏与布局 hooks +│ ├── plugins/ # Element Plus、ECharts 等插件注册入口 +│ ├── router/ # 静态路由、剩余路由、路由实例与守卫 +│ ├── store/ # Pinia store,含用户、权限、标签页、主题等模块 +│ ├── style/ # 全局样式、主题、暗色模式、侧边栏和过渡样式 +│ ├── utils/ # 鉴权、HTTP、缓存、消息、进度条、树处理等工具 +│ └── views/ # 页面视图,当前业务页在 employees、roles、stores +├── types/ # 全局类型声明、组件声明、路由声明和 Vue shim +├── AGENTS.md # Codex/Agent 入口规则,转到 RTK.md +├── RTK.md # 本仓库协作规则与 README 同步要求 +├── Dockerfile # 容器构建入口 +├── package.json # 依赖、脚本、engines 与 pnpm preinstall 限制 +├── pnpm-lock.yaml # pnpm 锁文件 +├── tsconfig.json # TypeScript 编译配置 +└── vite.config.ts # Vite 开发代理、插件、构建输出配置 +``` + +> 当前仓库不是 monorepo,没有 `packages/` 目录;重要脚本集中在 `package.json` 的 `scripts` 字段。 + +## 重要脚本 + +| 脚本 | 作用 | 使用场景 | +| --------------------- | ----------------------------------------------------------------------- | -------------------- | +| `pnpm dev` | 启动 Vite 开发服务,默认端口来自 `.env.development` 的 `VITE_PORT=8848` | 本地开发 | +| `pnpm serve` | `pnpm dev` 的别名 | 兼容习惯命令 | +| `pnpm build` | 清理 `dist` 后执行生产构建,内存上限设为 8192MB | 发布前打包 | +| `pnpm build:staging` | 使用 `staging` mode 构建 | 预发布环境验证 | +| `pnpm report` | 构建并打开 Rollup 可视化分析报告 | 分析包体积 | +| `pnpm preview` | 预览已有 `dist` 构建产物 | 构建后本地验收 | +| `pnpm preview:build` | 先构建再预览 | 一步完成打包验收 | +| `pnpm typecheck` | 执行 `tsc --noEmit` 和 `vue-tsc --noEmit --skipLibCheck` | 类型检查 | +| `pnpm lint` | 依次执行 ESLint、Prettier、Stylelint 自动修复 | 提交前整理代码 | +| `pnpm lint:eslint` | 对 `src`、`mock`、`build` 下 JS/TS/Vue 做 ESLint 修复 | 脚本或逻辑代码调整后 | +| `pnpm lint:prettier` | 格式化 `src` 下常见源码与文档格式 | 样式统一 | +| `pnpm lint:stylelint` | 修复 HTML/Vue/CSS/SCSS 样式规则 | 样式文件调整后 | +| `pnpm svgo` | 递归压缩 SVG | SVG 资源变更后 | +| `pnpm clean:cache` | 删除缓存、锁文件、依赖并重新安装 | 依赖状态异常时 | + +## 业务模块 + +- `src/views/stores/index.vue`: 门店管理,支持列表筛选、新增、编辑、启停和删除。 +- `src/views/roles/index.vue`: 角色管理,支持角色编码校验、新增、编辑和删除。 +- `src/views/employees/index.vue`: 员工管理,支持门店/状态/关键词筛选、分页、新增、编辑、启停和软删除。 +- `src/api/access.ts`: 门店、角色、员工接口类型与 HTTP 方法封装。 +- `src/router/modules/employees.ts`: 权限管理菜单入口,挂载门店、角色、员工三个页面。 + ## 后端对接 -开发环境通过 Vite 代理把 `/api` 转发到 `http://localhost:3500`,配置位于: +开发环境通过 Vite 代理把 `/api` 转发到 `VITE_API_PROXY_TARGET`,默认值为 `http://localhost:3500`。相关配置位于: - `.env.development` - `vite.config.ts` @@ -63,6 +131,23 @@ http://localhost:8848/ - `PATCH /api/employees/:id/status` - `DELETE /api/employees/:id` +接口响应统一在 `src/api/access.ts` 中使用 `ApiResult` 或 `PaginatedData` 描述,页面层只消费 `result.data`,避免在视图里重复拼接接口路径。 + +## 配置说明 + +- `.env`: 全局默认配置,目前包含端口和是否隐藏首页。 +- `.env.development`: 开发环境端口、路由模式、API 代理目标。 +- `.env.staging`: 预发布构建配置,可开启 CDN。 +- `.env.production`: 生产构建配置。 +- `public/platform-config.json`: pure-admin 运行时平台配置,例如标题、布局、主题、标签页和菜单搜索历史。 + +## 协作与文档同步 + +- 文件结构、入口文件、业务模块、脚本或关键配置发生变化时,必须同步更新本 README 的「目录说明」「重要脚本」或对应说明段落。 +- 仓库内提供 `.codex/skills/readme-structure-sync/SKILL.md`,用于提醒 Agent 在结构变更后维护 README。 +- `AGENTS.md` 指向 `RTK.md`,后续 Codex/Agent 进入仓库时应先遵守其中的协作规则。 +- 注释优先解释业务边界、接口契约、路由挂载、状态流转和容易误改的模板机制;不要给显而易见的语句堆叠无价值注释。 + ## 验证命令 ```bash diff --git a/RTK.md b/RTK.md new file mode 100644 index 0000000..0839991 --- /dev/null +++ b/RTK.md @@ -0,0 +1,20 @@ +# role-admin 协作规则 + +## 基本约定 + +- 使用 `pnpm`,不要引入 `npm`、`yarn` 或 `bun` 锁文件。 +- 业务接口统一放在 `src/api/access.ts`,页面层不要直接拼接后端 URL。 +- 权限管理菜单集中在 `src/router/modules/employees.ts`,默认标签页入口集中在 `src/layout/types.ts`。 +- 页面注释只解释业务边界、接口契约、状态流转和容易误改的模板机制,不做机械逐行注释。 + +## README 同步要求 + +- 只要新增、删除、移动目录或关键入口文件,就必须同步更新 `README.md` 的「目录说明」。 +- 只要新增、删除、重命名 `package.json` 中的关键脚本,就必须同步更新 `README.md` 的「重要脚本」。 +- 只要新增业务模块、接口模块、路由模块或环境配置,就必须同步更新 `README.md` 的对应说明。 +- 如果一次任务只触达局部文件,也要至少补齐当前任务相关的 README 内容;大范围遗留问题需要在交付说明里明确。 + +## 验证 + +- 文档或注释改动至少执行 `pnpm typecheck`。 +- 涉及源码、路由、构建配置或依赖脚本时,同时执行 `pnpm build`。 diff --git a/src/api/access.ts b/src/api/access.ts index 066be22..abd441c 100644 --- a/src/api/access.ts +++ b/src/api/access.ts @@ -1,10 +1,18 @@ import { http } from "@/utils/http"; +/** + * 门店权限后台的业务接口层。 + * + * 页面只依赖这里导出的类型和方法,避免在视图组件中散落接口路径、 + * 响应结构和状态枚举。后端统一挂在 `/api` 前缀下,由 Vite 代理转发。 + */ const API_PREFIX = "/api"; +/** 后端员工与门店共用的启停状态枚举。 */ export type EmployeeStatus = "ACTIVE" | "INACTIVE"; export type StoreStatus = "ACTIVE" | "INACTIVE"; +/** 员工列表中展示的角色摘要。 */ export interface RoleSummary { id: number; code: string; @@ -49,6 +57,7 @@ export interface Role extends RoleOption { updatedAt: string; } +/** 员工列表是服务端分页,门店和角色当前由前端做轻量筛选。 */ export interface EmployeeListParams { storeId?: number; status?: EmployeeStatus; @@ -83,6 +92,7 @@ export interface EmployeePayload { roleIds: number[]; } +/** access-manage 后端普通响应包裹结构。 */ export interface ApiResult { success: boolean; data: T; @@ -100,6 +110,7 @@ export interface PaginatedData { pagination: Pagination; } +/** 门店接口:管理门店基础资料,并给员工下拉选项提供数据源。 */ export const listStores = (params?: StoreListParams) => { return http.request>("get", `${API_PREFIX}/stores`, { params @@ -130,6 +141,7 @@ export const deleteStore = (id: number) => { return http.request("delete", `${API_PREFIX}/stores/${id}`); }; +/** 角色接口:维护员工可绑定的权限角色。 */ export const getRole = (id: number) => { return http.request>("get", `${API_PREFIX}/roles/${id}`); }; @@ -150,6 +162,7 @@ export const deleteRole = (id: number) => { return http.request("delete", `${API_PREFIX}/roles/${id}`); }; +/** 员工接口:员工列表由后端分页,编辑时按 id 重新拉取完整角色绑定。 */ export const listEmployees = (params: EmployeeListParams) => { return http.request>>( "get", diff --git a/src/layout/types.ts b/src/layout/types.ts index 93405b1..4ffe01f 100644 --- a/src/layout/types.ts +++ b/src/layout/types.ts @@ -1,5 +1,11 @@ import type { FunctionalComponent } from "vue"; +/** + * 登录后默认打开的标签页。 + * + * 这里要和 `src/router/modules/employees.ts` 的业务页面保持一致, + * 否则登出重置标签页或首次进入后台时会出现空标签/错入口。 + */ export const routerArrays: Array = [ { path: "/stores", diff --git a/src/router/modules/employees.ts b/src/router/modules/employees.ts index 610ebaa..f242b64 100644 --- a/src/router/modules/employees.ts +++ b/src/router/modules/employees.ts @@ -1,5 +1,11 @@ const Layout = () => import("@/layout/index.vue"); +/** + * 权限管理业务菜单。 + * + * 三个子页面都是静态路由,菜单展示顺序由这里的 children 决定; + * 默认访问该模块时进入员工管理,保证和登录/登出后的主工作流一致。 + */ export default { path: "/access", name: "AccessManagement", diff --git a/src/router/modules/home.ts b/src/router/modules/home.ts index 8db1698..46b4ddd 100644 --- a/src/router/modules/home.ts +++ b/src/router/modules/home.ts @@ -1,5 +1,11 @@ const Layout = () => import("@/layout/index.vue"); +/** + * pure-admin 模板要求保留 Home 根路由。 + * + * 当前业务首页是员工管理,所以根路径直接重定向到 `/employees`; + * `/welcome` 只作为隐藏工作台占位页保留。 + */ export default { path: "/", name: "Home", diff --git a/src/views/employees/index.vue b/src/views/employees/index.vue index ddd44c9..0636d98 100644 --- a/src/views/employees/index.vue +++ b/src/views/employees/index.vue @@ -34,10 +34,12 @@ defineOptions({ name: "EmployeeManagement" }); +/** 表单状态复用后端员工 payload,id 用来切换创建/更新接口。 */ type EmployeeFormState = EmployeePayload & { id?: number; }; +/** 员工手机号按中国大陆手机号做前端第一层校验,最终唯一性仍由后端保证。 */ const phonePattern = /^1[3-9]\d{9}$/; const tableLoading = ref(false); const catalogLoading = ref(false); @@ -56,6 +58,7 @@ const query = reactive({ pageSize: 20 }); +/** 员工列表由后端分页,这里只保存当前查询返回的分页摘要。 */ const pagination = reactive({ total: 0, totalPages: 0 @@ -130,6 +133,7 @@ function resetFormState() { formRef.value?.clearValidate(); } +/** 清理提交数据,避免把仅包含空格的备注写入后端。 */ function buildPayload(): EmployeePayload { return { storeId: form.storeId, @@ -141,6 +145,7 @@ function buildPayload(): EmployeePayload { }; } +/** 门店和角色是员工表单的基础字典,打开弹窗前必须先加载。 */ async function fetchCatalog() { catalogLoading.value = true; try { @@ -157,6 +162,7 @@ async function fetchCatalog() { } } +/** 员工列表筛选、分页都交给后端,前端只传递当前查询条件。 */ async function fetchEmployees() { tableLoading.value = true; try { @@ -207,6 +213,7 @@ function openCreateDialog() { dialogVisible.value = true; } +/** 编辑前重新拉详情,确保角色绑定不是来自列表摘要的过期数据。 */ async function openEditDialog(row: Employee) { try { const result = await getEmployee(row.id); diff --git a/src/views/roles/index.vue b/src/views/roles/index.vue index 89b2366..e74d0a9 100644 --- a/src/views/roles/index.vue +++ b/src/views/roles/index.vue @@ -25,10 +25,12 @@ defineOptions({ name: "RoleManagement" }); +/** 表单状态与角色 payload 对齐,id 只在编辑已有角色时存在。 */ type RoleFormState = RolePayload & { id?: number; }; +/** 角色编码用于权限判断,限制为稳定的小写标识,避免展示名变更影响授权逻辑。 */ const codePattern = /^[a-z][a-z0-9_]*$/; const tableLoading = ref(false); const submitLoading = ref(false); @@ -65,6 +67,7 @@ const rules: FormRules = { ] }; +/** 角色列表当前不分页,搜索在前端完成,降低简单维护场景的交互成本。 */ const filteredRoles = computed(() => { const keyword = query.keyword.trim().toLowerCase(); @@ -119,6 +122,7 @@ function resetFormState() { formRef.value?.clearValidate(); } +/** 空说明统一转为 null,和后端可选字段语义保持一致。 */ function buildPayload(): RolePayload { const description = form.description?.trim(); @@ -129,6 +133,7 @@ function buildPayload(): RolePayload { }; } +/** 角色是员工绑定的基础字典,页面加载和保存后都需要刷新。 */ async function fetchRoles() { tableLoading.value = true; try { diff --git a/src/views/stores/index.vue b/src/views/stores/index.vue index 0bcf393..417af7b 100644 --- a/src/views/stores/index.vue +++ b/src/views/stores/index.vue @@ -28,6 +28,7 @@ defineOptions({ name: "StoreManagement" }); +/** 表单状态与后端 payload 基本一致,额外用 id 区分新增和编辑。 */ type StoreFormState = StorePayload & { id?: number; }; @@ -62,6 +63,7 @@ const rules: FormRules = { status: [{ required: true, message: "请选择门店状态", trigger: "change" }] }; +/** 门店数据量预计较小,列表一次性拉取后在前端做状态和关键词筛选。 */ const filteredStores = computed(() => { const keyword = query.keyword.trim().toLowerCase(); @@ -117,6 +119,7 @@ function resetFormState() { formRef.value?.clearValidate(); } +/** 提交前统一清理空字符串,保持后端收到的是 null 而不是空值。 */ function buildPayload(): StorePayload { const address = form.address?.trim(); const phone = form.phone?.trim(); @@ -129,6 +132,7 @@ function buildPayload(): StorePayload { }; } +/** 拉取包含停用门店的完整列表,便于后台直接做启停管理。 */ async function fetchStores() { tableLoading.value = true; try {