feat: 初始化项目结构并添加基础配置

添加前后端基础项目结构,包括.gitignore、package.json等配置文件
实现前端基础功能模块,包括路由、状态管理、API请求封装等
添加前端UI组件库和样式体系
配置开发环境Mock系统和构建工具链
This commit is contained in:
2026-03-18 14:03:35 +08:00
parent fc53f5620e
commit 9a387f3eec
504 changed files with 80629 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/back-end/node_modules

30
.trae/rules/bai.md Normal file
View File

@@ -0,0 +1,30 @@
---
alwaysApply: false
---
# 角色与核心哲学 (Role & Core Philosophy)
你是一名具备全栈思维的全语言工程师Polyglot Engineer
---
# 绝对拦截规则 (Execution Barriers)
任何时候,当你要开始编写、修改、重构或输出具体业务`代码`前,必须且只能先完成 `<OpenSpec 自动化工作流>`
---
# <OpenSpec 自动化工作流> (强制状态流转)
### Step 1: 核心流 - 环境检查与锚点确认 (强制第一步)
- 动作:扫描当前工作区文件
- 判断逻辑:
- IF 发现 `openspec` 相关配置 或 `spec/` 目录存在 -> 判定为规范已初始化,进入 Step 2
- IF NOT -> 必须触发初始化流程:
- 优先检查 Node 生态:判断是否有 `package.json`。若无,优先建议执行 `npm init`
- 强烈建议并通过 `npx` 相关的命令来初始化规范工具,坚决避免全局污染
### Step 2: 规格流 - 提案与生成 (强制第二步)
- 动作:在构思架构前,必须调用或输出以下内容:
- `openspec-proposal`:必须优先检索并推荐 npm 仓库中成熟的开源包,拒绝无意义的重复造轮子。将包名和版本策略写入提案
- `openspec-apply`:生成详细技术规格时,优先采用 Node.js 的最佳实践
# 强制交互格式 (Interaction Protocol)
内部逻辑思考使用英文,用户交互使用专业、简洁的中文
在调用任何 Skill、执行命令、或开始输出任何代码前你的第一条回复必须严格按照以下格式向用户播报
> 执行前置检查...
> - 当前生态:[强调 Node.js 与 npm 的介入策略,或说明当前的替代环境]
> - 当前动作:[例如:正在调用 openspec-proposal 规划架构...]

15
back-end/.env Normal file
View File

@@ -0,0 +1,15 @@
# Server Configuration
PORT=3000
# Environment
NODE_ENV=development
# API Configuration
API_PREFIX=/api
# Database Configuration (placeholder)
DB_HOST=localhost
DB_PORT=5432
DB_NAME=bai_management
DB_USER=postgres
DB_PASSWORD=password

2039
back-end/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

26
back-end/package.json Normal file
View File

@@ -0,0 +1,26 @@
{
"name": "web-bai-manage-api-server",
"version": "1.0.0",
"description": "Backend API server for BAI Management System",
"main": "src/index.js",
"scripts": {
"dev": "node src/index.js",
"build": "echo 'No build needed for backend'",
"test": "echo 'No tests implemented yet'",
"lint": "echo 'No linting implemented yet'",
"spec:lint": "npx @fission-ai/openspec lint spec/",
"spec:validate": "npx @fission-ai/openspec validate spec/"
},
"dependencies": {
"express": "^4.18.2",
"dotenv": "^16.3.1"
},
"devDependencies": {
"@fission-ai/openspec": "^1.0.0"
},
"engines": {
"node": ">=22.0.0"
},
"author": "",
"license": "ISC"
}

View File

@@ -0,0 +1,48 @@
openapi: 3.1.0
info:
title: BAI Management API
description: Backend API for BAI Management System
version: 1.0.0
servers:
- url: http://localhost:3000
description: Development server
paths:
/test-helloworld:
get:
summary: Test endpoint
description: Returns a hello world message
responses:
'200':
description: Successful response
content:
application/json:
schema:
type: object
properties:
message:
type: string
example: Hello, World!
timestamp:
type: string
format: date-time
status:
type: string
example: success
/health:
get:
summary: Health check
description: Checks if the server is running
responses:
'200':
description: Server is healthy
content:
application/json:
schema:
type: object
properties:
status:
type: string
example: healthy
timestamp:
type: string
format: date-time

35
back-end/src/index.js Normal file
View File

@@ -0,0 +1,35 @@
const express = require('express');
const dotenv = require('dotenv');
// 加载环境变量
dotenv.config();
const app = express();
const port = process.env.PORT || 3000;
// 解析JSON请求体
app.use(express.json());
// 测试接口
app.get('/test-helloworld', (req, res) => {
res.json({
message: 'Hello, World!',
timestamp: new Date().toISOString(),
status: 'success'
});
});
// 健康检查接口
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString()
});
});
// 启动服务器
app.listen(port, () => {
console.log(`Server running on port ${port}`);
console.log(`Test endpoint: http://localhost:${port}/test-helloworld`);
console.log(`Health check: http://localhost:${port}/health`);
});

86
docs/project.md Normal file
View File

@@ -0,0 +1,86 @@
开发框架约束(供 AI 创建项目使用)
目的:本文件用于约束 AI 在创建/改造项目时的技术选型、目录结构、工程化与交付流程。除非明确得到人工指令,否则 AI 不得偏离本文件的约束。
1. 运行环境与基础约束
- Node.js 版本:必须使用 Node.js 22+(建议使用最新 LTS
- 主要语言JavaScript.js为主。
- 允许在必要时引入类型检查方案(例如 JSDoc + // @ts-check但默认不将 TypeScript 作为主要语言。
- 包管理器:**强制统一使用 `npm`**。
- 跨平台:默认需兼容 WindowsPowerShell与类 Unix 环境。
2. 技术栈约束
2.1 前端
- 框架:必须使用 Vue 3.x。
- 生态库:仅引入与 Vue 3.x 兼容的相关库;避免引入与 Vue 2.x 绑定的历史库。
- 构建工具:优先 Vite如与既有工程冲突需说明原因并保持一致性
2.2 后端
- 运行时:必须使用 Node.js。
- 语言:后端同样以 JavaScript 为主。
- API 风格:默认使用 HTTP JSON API如采用 GraphQL/WebSocket 等需明确说明并仍遵循 OpenSpec 约束)。
3. OpenSpec规范驱动开发流程约束
> 说明:这里的 OpenSpec 指通过全局安装 `@fission-ai/openspec` 获得的规范驱动工具链;在 API 场景下,接口契约必须使用并遵守 OpenAPI 3.1。两者不冲突OpenSpec 用于驱动/校验流程OpenAPI 3.1 是规范文件中必须满足的契约。
3.0 OpenSpec 工具链安装(强制)
- 开发与 CI 环境必须确保可用的 OpenSpec 工具链:
- 安装命令npm install -g @fission-ai/openspec@latest
- AI 在生成项目脚本时:
- 必须将规范校验能力接入到 npm scripts见 3.3)。
- 不得绕过 OpenSpec 校验直接交付“未受规范约束”的 API 实现。
3.1 必须交付的规范产物
- 项目必须包含一个可追溯的规范文件:
- API 项目:`spec/openapi.yaml`(或 `spec/openapi.json`),版本 OpenAPI 3.1。
- 非 API 项目:仍需提供对应的“规格说明”(例如流程/数据结构/输入输出契约),放在 spec/ 目录下。
- 规范文件需满足:
- 可被校验lint/validate
- 与实现一致(实现变更必须同步更新规范)
3.2 开发顺序(强制)
1. 先写/更新规范spec-first在新增/修改功能前,先更新 `spec/` 下的规范。
2. 再实现:实现必须与规范一致。
3. 再验证CI/本地脚本必须包含规范校验步骤。
4. 再文档化README 中必须说明如何查看/使用规范与如何运行校验。
3.3 规范校验与联动(强制)
- 必须提供脚本(示例命名,可按项目调整但不可缺失):
- npm run spec:lint调用 OpenSpec 对 spec/ 做 lint具体 CLI 参数以 openspec --help 为准)
- npm run spec:validate调用 OpenSpec 对 spec/ 做结构/引用/契约校验(具体 CLI 参数以 openspec --help 为准)
- 若为 API
- 必须在实现层提供请求/响应校验或至少在测试阶段进行契约校验。
- 鼓励(非强制)从 OpenAPI 生成 client/server stub 或生成类型定义但不得改变“JS 为主语言”的前提。
4. 工程结构约束(建议默认)
AI 创建项目时,默认使用以下结构;如项目类型不适用,可在不违背约束的前提下做最小调整。
- spec/OpenSpec 规范OpenAPI 或其他规格说明)
- src/:源代码
- tests/:测试
- scripts/:工程脚本(构建/校验/生成等)
- README.md必须包含运行、测试、规范使用方式
5. 质量与交付约束(强制)
- 必须提供基础脚本:
- npm run dev如可交互开发
- npm run build如需要构建
- npm run test
- npm run lint
- 变更要求:
- 修改实现时同步更新 spec/ 与测试。
- 不得只改实现不改规范;也不得只改规范不改实现。
6. AI 行为约束(强制)
- 若用户需求与本文件冲突:
- 先指出冲突点,并请求用户确认是否允许偏离约束。
- 未明确要求时:
- 不引入与约束无关的“额外页面/功能/组件/花哨配置”。
- 保持最小可用、可验证、可维护的实现。

View File

@@ -0,0 +1,4 @@
> 1%
last 2 versions
not dead
not ie 11

12
front-end/.editorconfig Normal file
View File

@@ -0,0 +1,12 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false

104
front-end/.env Normal file
View File

@@ -0,0 +1,104 @@
# Vab Admin 系列产品受国家计算机软件著作权保护(证书号:软著登字第 7051316 号)。
# 关于举报盗版侵权请发送举报材料至我司客服邮箱1204505056@qq.com一经查实官司所得收入20%归举报人所有80%归律师事务所所有。
# Vue Admin系列产品购买地址//vuejs-core.cn/authorization
# 1.购买者可将授权后的产品用于任意「符合国家法律法规」的应用平台,禁止用于黄赌毒等危害国家安全与稳定的网站。
# 2.购买主体购买后可用于开发商业项目,不限制域名和项目数量,购买主体不可将源码分享第三方,否则我们有权利收回产品授权及更新权限,并根据事态轻重追究相应法律责任。
# 3.购买者务必尊重知识产权,严格保证不恶意传播产品源码、不得直接对授权的产品本身进行二次转售或倒卖、开源、不得对授权的产品进行简单包装后声称为自己的产品等,无论有意或无意,我们有权利收回产品授权及更新权限,并根据事态轻重追究相应法律责任。
# 4.购买者不可将vip群文档及资料分享给第三方否则我们有权利收回产品授权及更新权限并根据事态轻重追究相应法律责任。
# 5.购买者购买项目不可以用来构建存在竞争性质的产品并直接对外销售否则我们有权利收回产品授权及更新权限,并根据事态轻重追究相应法律责任。
# 6.购买者购买项目中的源码(包含全部源码、及部分源码片段)不可以用于任何形式的开源项目,否则我们有权利收回产品授权及更新权限,并根据事态轻重追究相应法律责任。
# 7.用于公司的项目商用时购买需提供公司名称,用于证明购买过我们的项目来用于商业用途,防范法律风险,我们不会将【购买公司】信息泄漏到互联网或告知第三方。
# 8.用于个人学习需提供姓名、联系方式。
# 9.如用于外包项目购买者购买项目中的源码不可直接对外出售npm run build编译后的项目不受限制。
# 10.虚拟物品不支持退货退款。
# 11.最终解释权归vab系列著作权人所有。
# 第1步请在此处将test变更为您的github用户名请务必填写购买时绑定的github用户名同一个授权配置不同用户名会导致您的授权永久失效
VUE_GITHUB_USER_NAME=MomoWen
# 第2步请在项目根目录新建一个.env.local的新文件切记是新建空的文件不是直接拷贝.env文件的内容
# 第3步.env.local的文件只能有一行不可以换行购买时生成格式如下VUE_APP_SECRET_KEY=XXXXXXX
# 以下内容不建议修改建议将VUE_APP_SECRET_KEY配置到【.env.local】中
VUE_APP_SECRET_KEY=preview

View File

@@ -0,0 +1,4 @@
# 开发环境VUE_APP_BASE_URL可以选择自己配置成需要的接口地址如"https://api.xxx.com"
# 此文件修改后需要重启项目
NODE_ENV=development
VUE_APP_BASE_URL='/vab-mock-server'

View File

@@ -0,0 +1,4 @@
# 生产环境VUE_APP_BASE_URL可以选择自己配置成需要的接口地址如"https://api.xxx.com"
# 此文件修改后需要重启项目
NODE_ENV=production
VUE_APP_BASE_URL='/vab-mock-server'

4
front-end/.env.test Normal file
View File

@@ -0,0 +1,4 @@
# 测试环境VUE_APP_BASE_URL可以选择自己配置成需要的接口地址如"https://api.xxx.com"
# 此文件修改后需要重启项目
NODE_ENV=production
VUE_APP_BASE_URL='/vab-mock-server'

7
front-end/.eslintignore Normal file
View File

@@ -0,0 +1,7 @@
library/build/vuePlugins/components.d.ts
node_modules
src/assets
src/icons
public
dist
vab-icons

81
front-end/.eslintrc.js Normal file
View File

@@ -0,0 +1,81 @@
const { defineConfig } = require('eslint-define-config')
module.exports = defineConfig({
root: true,
env: {
node: true,
browser: true,
},
globals: {
defineOptions: 'writable',
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module',
ecmaVersion: 2020,
},
rules: {
'import-x/order': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-this-alias': 'off',
'array-callback-return': 'off',
'escape-case': 'off',
'eslint-comments/no-unlimited-disable': 'off',
'import/order': 'off',
'no-alert': 'off',
'no-console': 'off',
'no-debugger': 'off',
'no-restricted-imports': 'off',
'no-return-await': 'off',
'prefer-const': 'off',
'prefer-template': 'error',
'unicorn/consistent-function-scoping': 'off',
'unicorn/escape-case': 'off',
'unicorn/filename-case': 'off',
'unicorn/import-style': 'off',
'unicorn/no-abusive-eslint-disable': 'off',
'unicorn/no-array-callback-reference': 'off',
'unicorn/no-array-for-each': 'off',
'unicorn/no-array-reduce': 'off',
'unicorn/no-nested-ternary': 'off',
'unicorn/no-null': 'off',
'unicorn/no-object-as-default-parameter': 'off',
'unicorn/no-process-exit': 'off',
'unicorn/no-this-assignment': 'off',
'unicorn/numeric-separators-style': 'off',
'unicorn/prefer-array-some': 'off',
'unicorn/prefer-default-parameters': 'off',
'unicorn/prefer-dom-node-append': 'off',
'unicorn/prefer-dom-node-remove': 'off',
'unicorn/prefer-logical-operator-over-ternary': 'off',
'unicorn/prefer-math-trunc': 'off',
'unicorn/prefer-module': 'off',
'unicorn/prefer-number-properties': 'off',
'unicorn/prefer-query-selector': 'off',
'unicorn/prefer-spread': 'off',
'unicorn/prefer-string-slice': 'off',
'unicorn/prefer-structured-clone': 'off',
'unicorn/prefer-ternary': 'off',
'unicorn/prefer-top-level-await': 'off',
'unicorn/prevent-abbreviations': 'off',
'unicorn/expiring-todo-comments': 'off',
'unicorn/consistent-destructuring': 'off',
'vue/multi-word-component-names': 'off',
'vue/no-reserved-component-names': 'off',
'vue/no-setup-props-destructure': 'off',
'vue/no-v-html': 'off',
'vue/require-default-prop': 'off',
'unicorn/number-literal-case': 'off',
'@typescript-eslint/no-var-requires': 'off',
'import/first': 'off',
'object-shorthand': 'off',
'unicorn/no-console-spaces': 'off',
'unicorn/prefer-dom-node-text-content': 'off',
'unicorn/prefer-code-point': 'off',
'@typescript-eslint/consistent-type-imports': 'off',
camelcase: 'off',
},
})

17
front-end/.gitattributes vendored Normal file
View File

@@ -0,0 +1,17 @@
*.html text eol=lf
*.css text eol=lf
*.js text eol=lf
*.ts text eol=lf
*.scss text eol=lf
*.vue text eol=lf
*.hbs text eol=lf
*.sh text eol=lf
*.md text eol=lf
*.json text eol=lf
*.yml text eol=lf
.browserslistrc text eol=lf
.editorconfig text eol=lf
.eslintignore text eol=lf
.gitattributes text eol=lf
LICENSE text eol=lf
*.conf text eol=lf

46
front-end/.gitignore vendored Normal file
View File

@@ -0,0 +1,46 @@
.DS_Store
node_modules
node_modules.nosync
/dist
# local env files
.env.local
.env.*.local
# Log files
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Lock files
yarn.lock
pnpm-lock.yaml
package-lock.json
# Yarn v2 not using using Zero-Installs
.yarn/*
#!.yarn/cache
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
# Vab
public/video
*.zip
*.7z
*.rar
/.history

1
front-end/.npmrc Normal file
View File

@@ -0,0 +1 @@
shamefully-hoist=true

View File

@@ -0,0 +1,4 @@
auto-imports.d.ts
components.d.ts
index.html
website.html

18
front-end/.stylelintrc.js Normal file
View File

@@ -0,0 +1,18 @@
module.exports = {
extends: [
'stylelint-config-recommended-scss',
'stylelint-config-recommended-vue',
'stylelint-config-recess-order',
],
rules: {
'no-empty-source': null,
'at-rule-no-unknown': null,
'property-no-unknown': null,
'function-no-unknown': null,
'selector-class-pattern': null,
'no-descending-specificity': null,
'scss/no-global-function-names': null,
'selector-pseudo-class-no-unknown': null,
},
ignoreFiles: ['dist/**/*', 'public/index.html'],
}

View File

@@ -0,0 +1,9 @@
# 00. 快速画像(给 AI 的 30 秒摘要)
- **技术栈**`Vue 3` + `Vue CLI 5` + `TypeScript` + `Pinia` + `Vue Router` + `Element Plus`
- **入口链路**`src/main.ts``setupVab(app)``setupI18n(app)``setupStore(app)``setupRouter(app)`
- **Mock**:开发环境由 `vue.config.js``mock/index.js` 挂载到 devServer 中间件;路由集合来自 `mock/controller/*`
- **别名**`@``src``@vab``library``~`→根目录,`/#``types`
- **用途定位**:既是可运行的后台 Demo也是可拆分的能力集合`library/layouts/ library/components/ library/ src/utils/ mock/ src/api/ types/`
> 推荐阅读顺序:本文件 → [01-Directory-Map.md](01-Directory-Map.md) → [AI-Reuse-Playbook.md](AI-Reuse-Playbook.md)

View File

@@ -0,0 +1,51 @@
# 01. 仓库地图Directory Map
> 目标:让 AI 快速定位“要复用的能力”在哪个目录、入口是什么、依赖闭包有哪些。
## `src/`(应用主代码)
- `src/main.ts`:应用入口;决定 mock/pwa 与各子系统初始化顺序
- `src/App.vue`:根组件;包含生产环境禁调试逻辑(`disable-devtool`
- `src/router/`:路由与权限控制(重点:`index.ts``permissions`
- `src/store/`Pinia 初始化与业务 store 模块
- `src/i18n/`:国际化初始化、语言获取与翻译辅助
- `src/api/`:按域拆分 API 调用函数(示例:`src/api/router.ts`
- `src/utils/`通用工具与基础能力时间格式化、树结构转换、UUID 等)
- `src/views/`:业务页面集合(通常与路由对应)
- `src/icon/`:图标加载(由 `library/index.ts` 里的 `import '@/icon'` 引入)
- `src/config/`:运行时/构建期配置聚合导出(`vue.config.js``require('./src/config')`
## `library/`(模板基础库)
- `library/index.ts``setupVab(app)` 的实现:
- 全局样式:`library/styles/vab.scss`
- 图标注册:`vab-icons` + `@element-plus/icons-vue`
- 背景样式:`library/styles/background/*.scss`
- 插件加载:`library/plugins/**/*.ts``app.use()`
- `library/build/`构建期扩展webpack chain、vue plugins
## `library/plugins/`(全局插件)
- `vab.ts`全局注入gp与事件总线`$pub/$sub/$unsub`
- `directive.ts`:指令(`v-permissions`
- `errorLog.ts`:全局错误捕获(`app.config.errorHandler`
- `support.ts`:构建信息输出/依赖检查
## `library/components/`(可复用 UI 组件库)
- `Vab*` 前缀:约定为基础组件/布局子组件菜单、tabs、header、breadcrumb 等)
- `VabTheme`:主题系统入口(主题抽屉/设置面板),依赖 `$pub/$sub` 与 settings store
## `library/layouts/`(布局体系)
- `library/layouts/index.vue`:主 Layout 入口(路由壳)
- `library/layouts/VabLayout*`:多套布局可选(垂直/横向/综合/浮动/分栏等)
## `mock/`(开发期 Mock
- `mock/index.js`devServer 中间件;读取并注册 `mock/controller/*`
- `mock/controller/*.js`:每个文件导出路由数组(`url/type/response`
## `types/`(类型声明)
- `types/*.d.ts`:路由/store/theme/vab 等声明,配合 `/#` 别名使用

View File

@@ -0,0 +1,28 @@
# 02. 关键入口与初始化顺序Boot Sequence
## 入口文件:`src/main.ts`
AI 需要知道“系统从哪里开始、按什么顺序挂载能力”。关键点:
1. `validateSecretKey()`:启动前校验(与授权/环境有关)
2. 生产环境 Mock
- 条件:`process.env.NODE_ENV === 'production'``baseURL` 不是外链(`!isExternal(baseURL)`
- 动作:`require('@/utils/static').mockXHR()`
3. 初始化链路:
- `setupVab(app)`(全局样式、图标、插件)
- `setupI18n(app)`
- `setupStore(app)`
- `setupRouter(app).isReady().then(mount)`
## 全局插件聚合:`library/index.ts`
`setupVab(app)` 做了这些事:
- 引入全局样式:`library/styles/vab.scss`
- 注册图标:
- `VabIcon`(来自 `vab-icons`
- `@element-plus/icons-vue` 全量组件注册
- 自动加载背景样式:`library/styles/background/*.scss`
- 自动加载插件:`library/plugins/**/*.ts`(默认导出 Vue 插件)
> 复用提示:自动全量加载在“抽取模块”时容易带入不必要依赖;迁移时应以“最小闭包”为原则(见 [AI-Reuse-Playbook.md](AI-Reuse-Playbook.md))。

View File

@@ -0,0 +1,23 @@
# 03. Mock 系统(开发联调与脱网演示)
## 挂载方式
- `vue.config.js``devServer.setupMiddlewares = require('./mock')`
- `mock/index.js`
- 将路由集合转换为 express 形式
- 使用 `mockjs` 返回数据
- 监听 `mock/` 变更并热更新(`chokidar`
## 路由定义约定(供 AI 生成/扩展)
`mock/controller/*.js` 中,每个路由对象通常包含:
- `url`:不含 `baseURL` 前缀的路径(中间件会自动拼上 `baseURL`
- `type``get` / `post` / ...
- `response(req, res)`:返回对象或函数
## AI 新增业务 API 的推荐动作
1) 在 `src/api/<domain>.ts` 新增函数(调用 `request({ url, method })`
2) 在 `mock/controller/<domain>.js` 新增对应 mock 路由,路径保持一致
3) 在模块规格中补充接口契约(建议写到 `openspec-lite/modules/<domain>.yaml`

View File

@@ -0,0 +1,46 @@
# 04. 路由与页面组织Router & Views
- 路由文件:`src/router/index.ts`
- 核心结构:
- `constantRoutes`:登录/注册/404 等公共路由
- `asyncRoutes`:业务路由,通常以 `Layout` 为根节点容器
## Views 目录约定src/views
本仓库页面主要集中在:
- `src/views/index/`:工作台/仪表盘等示例首页
- `src/views/vab/`:组件/表单/表格等示例页(演示用途居多)
- `src/views/other/`杂项示例页iframe/excel/drag/nested 等)
- `src/views/setting/`:后台管理相关页面(用户/角色/部门/菜单/字典/任务/日志等)
- `src/views/tools/`:工具类页面(如 EyeDropper/SpeechSynthesis
- `src/views/login/``src/views/register/``src/views/callback/`:登录链路
- `src/views/403.vue``src/views/404.vue`:错误页
路由对页面的引用方式以动态导入为主:`component: () => import('@/views/...')`
## meta 约定(给菜单/面包屑/行为用)
常见 meta 字段(与组件实现强相关):
- `meta.title`:菜单/面包屑/页面标题(`VabLanguage` 会用它更新 `document.title`
- `meta.icon` + `meta.isCustomSvg`:菜单与面包屑图标(`VabMenu`/`VabBreadcrumb`
- `meta.hidden`:是否从菜单隐藏(`VabMenu`
- `meta.breadcrumbHidden`:是否从面包屑隐藏(`VabBreadcrumb`
- `meta.noColumn`Column 布局下的特殊处理(`VabColumnBar` 会折叠菜单并隐藏 fold 按钮)
- `meta.target`(如 `_blank`):点击菜单时打开方式(`VabMenuItem`
- `meta.badge` / `meta.dot`:菜单右侧标记(`VabMenuItem`
## AI 生成新模块页面的最小流程
-`src/views/<module>/` 创建页面组件
-`src/router/index.ts`(或其拆分文件)添加路由记录
- 如涉及权限/菜单:同步 `meta``title/icon/guard/...`
建议:新增页面后运行一次 [AI-Coding/Validation.md](AI-Coding/Validation.md) 里的“router ↔ views 对账”脚本,防止路由引用了不存在的 .vue或新页面忘记挂到路由上。
## 验收点
- 访问路由能渲染页面
- 菜单与面包屑符合 `meta` 约定
- 刷新后路由仍可恢复

View File

@@ -0,0 +1,16 @@
# 05. 状态管理Pinia Store
- `src/store/index.ts``createPinia()``app.use(pinia)`
- i18n 语言读取:`src/i18n/index.ts` 通过 `useSettingsStore(pinia)` 获取语言
## AI 提取/迁移注意
- 迁移 `src/store/index.ts` 时,通常也需要迁移:
- `src/store/modules/settings.ts`(见 `12-Settings-Store.md` / `openspec-lite/modules/store-settings.yaml`
- `src/store/modules` 下其它基础模块(见 `14-Store-Modules.md`
- 与其相关的类型(`types/`,即 `/#` 别名指向的目录)
## 验收点
- Store 能正常注入
- 关键 store如 settings能在不报错情况下读取

View File

@@ -0,0 +1,17 @@
# 06. 国际化i18n
- 文件:`src/i18n/index.ts`
- 关键点:
- `legacy: false`Composition API 模式)
- 内置 `en``zh` 为空对象(等待补充)
- 提供 `translate(message)` 辅助函数
- 导出 Element Plus 语言包:`enLocale` / `zhLocale`
## 扩展建议
- 新增语言:在 `src/i18n/locales/` 添加 `xx.json` 并合并到 `messages`
## 验收点
- 切换语言后页面能按预期渲染
- Element Plus 语言包切换有效

View File

@@ -0,0 +1,17 @@
# 07. API 层(请求封装与域拆分)
- 示例:`src/api/router.ts` 调用 `request({ url: '/router/getList', method: 'get' })`
- 请求封装:`src/utils/request.ts`axios 拦截器、token 注入、401/402/403 处理、错误提示)
- 刷新令牌:`src/api/refreshToken.ts`402 时重试队列)
- 请求异常入库:通过 `@vab/plugins/errorLog`(见 `library/plugins/errorLog.ts`
## AI 复用原则
- 以“域”为单位抽取:`src/api/<domain>.ts`
- 抽取前先定位 `request` 封装(通常在 `src/utils/request` 或相近位置)
- 若新项目变更 baseURL/token/error 规范,优先在规格里声明差异,然后再做迁移适配
## 验收点
- 基础请求能发起
- 错误处理与鉴权逻辑符合项目约束

View File

@@ -0,0 +1,20 @@
# 08. Alias 与类型(迁移必须同步)
## Alias
- `@``src`
- `~` → 根目录
- `/#``types`
- `@vab``library`
- `@gp``library/plugins/vab`
来源:`vue.config.js``tsconfig.json`
## 类型声明
- `types/*.d.ts`:路由/store/theme/vab 等声明
## 迁移到不同构建工具(如 Vite时的最低要求
- alias 需要在新工具里重新配置
- `types/` 需要进入 tsconfig 的 `include`

View File

@@ -0,0 +1,15 @@
# 09. 代码生成Plop
- 文件:`plopfile.js`
- 生成器:`view` / `curd` / `component` / `mock&api`
运行:
```powershell
pnpm run template
```
## AI 使用建议
- 如果后续 AI 以“生成代码”为策略,可优先复用 plop 模板,而不是从零写
- 新增生成器前,先在 `openspec-lite/project.yaml` 里补充命名/目录约束

View File

@@ -0,0 +1,38 @@
# 10. Theme 系统VabTheme + settings
> 目标:让 AI 在抽取/复用 Layout 时,不会漏掉主题抽屉、事件总线与 settings 的主题变量闭包。
## 入口与组成
- 主题入口组件:`library/components/VabTheme/index.vue`
- 主题抽屉:`library/components/VabTheme/components/VabThemeDrawer.vue`
- 主题设置入口:`library/components/VabTheme/components/VabThemeSetting.vue`
- 主题状态与持久化:`src/store/modules/settings.ts`
## 关键机制
- 事件总线:通过 `library/plugins/vab.ts` 注入 `$pub/$sub/$unsub`
- 打开抽屉:`$pub('theme')`
- 随机换肤:`$pub('random-theme')`
- 主题应用:`useSettingsStore().updateTheme()`
- 动态 `require(@vab/styles/variables/vab-*-variables.module.scss)`
-`vab-` 前缀变量映射到 `--el-` CSS 变量
- 设置 `body` class`vab-theme-*`)与背景类
## 最小依赖闭包(抽取时必须带上)
- `library/components/VabTheme/`
- `src/store/modules/settings.ts`(至少 theme/showTheme/saveTheme/resetTheme/updateTheme
- `library/plugins/vab.ts`(提供 `$pub/$sub``$baseLoading`
- `library/styles/variables/`(所有 `vab-*-variables.module.scss`
- Element Plus + i18n组件内有 `translate()` 与 el-* 组件)
## 验收点smoke
- 触发 `$pub('theme')` 抽屉能打开/关闭
- 保存/重置主题后,刷新页面主题能持久化且变量生效
## 常见坑
- `updateTheme()` 使用 webpack 风格的动态 `require`:迁移到非 webpack 构建(如部分 Vite 场景)需要等效实现
- 主题抽屉/设置依赖事件总线注入:未安装 `vab` 插件时会“看起来渲染了但不工作”

View File

@@ -0,0 +1,29 @@
# 11. Plugins 系统library/plugins/*
> 目标:明确本仓库“全局注入能力/指令/错误处理”的来源,避免抽取组件时漏掉运行时注入。
## 插件目录
- `library/plugins/vab.ts`:全局 gp 注入 + mitt 事件总线(`$pub/$sub/$baseMessage/...`
- `library/plugins/directive.ts`:自定义指令(`v-permissions`
- `library/plugins/errorLog.ts`:全局错误捕获(`app.config.errorHandler`)并写入 store
- `library/plugins/support.ts`:构建信息输出与依赖存在性检查
## 安装方式
- 正常路径:`library/index.ts` 会自动加载 `library/plugins/**/*.ts``app.use()`setupVab 链路内)
- 抽取到目标项目:
- 若不复用 `library/index.ts` 的自动加载逻辑,需要在入口手动 `app.use(plugin)`
## 最小依赖闭包
- `vab.ts`:依赖 Element Plus 全局 APIElMessage/ElLoading/ElMessageBox/ElNotification+ lodash + mitt + `src/config`
- `directive.ts`:依赖 `src/utils/permission`hasPermission 及其权限数据来源)
- `errorLog.ts`:依赖 `src/store/modules/errorLog``src/config/errorLog`
- `support.ts`:依赖 `__APP_INFO__` 构建注入
## 验收点smoke
- `vab``$baseMessage('ok')` 能弹出 message`$pub/$sub` 能收发事件
- `directive`:模板中 `v-permissions` 不报错且能按权限生效
- `errorLog`:手动触发异常能写入 errorLog store

View File

@@ -0,0 +1,35 @@
# 12. Settings Store主题/布局等全局配置)
> 目标:把 Theme/Layout 的“根依赖”讲清楚,避免 AI 抽取时只搬组件却漏掉主题变量注入与持久化逻辑。
## 入口
- `src/store/modules/settings.ts``useSettingsStore`
## 管理的核心状态
- `theme`:包含 `layout/themeName/background/menuWidth/showTheme/showThemeSetting/tabsBarStyle...`
- `device``desktop | mobile`(布局响应式需要)
- `collapse`:侧边栏折叠状态
- `language`:国际化语言
## 关键动作
- `saveTheme()`:持久化 theme
- `resetTheme()`:恢复默认 theme并调用 `updateTheme()`
- `updateTheme()`
- 通过 `@vab/styles/variables/vab-*-variables.module.scss` 读取变量
-`vab-` 前缀映射到 `--el-`,动态写入 Element Plus CSS 变量
- 设置 body class`vab-theme-*`,并按 background 追加 class
- 设置 `--el-left-menu-width`
## 最小闭包Theme/Layout 抽取必须带上)
- `src/store/modules/settings.ts`
- `library/styles/variables/vab-*-variables.module.scss`
- `library/plugins/vab.ts`Theme 事件总线注入)
## 常见坑
- `updateTheme()` 使用 webpack 风格动态 `require`,迁移到非 webpack 构建器需要等效替代
- `useCssVar` 的导入方式依赖工程约定(自动导入 vs 显式 import

View File

@@ -0,0 +1,70 @@
# 13. 组件清单library/components
> 目的:让 AI 在新项目中“选组件/抽组件”时,先从**可复用目录清单**开始,避免漏组件或重复造轮子。
## 组件根目录
- `library/components/`(约定:每个 `Vab*` 目录是一组可复用组件)
## 当前组件目录(按仓库实际目录列出)
- `VabApp`:应用壳/全局 Provider
- `VabAppMain`:主内容区(与 Layout 配合)
- `VabAvatar`
- `VabBreadcrumb`
- `VabCard`
- `VabColorfulCard`
- `VabColumnBar`
- `VabErrorLog`
- `VabFold`
- `VabFooter`
- `VabFullScreen`
- `VabHeader`
- `VabLanguage`
- `VabLink`
- `VabLock`
- `VabLogo`
- `VabMenu`
- `VabNav`
- `VabNotice`
- `VabQueryForm`
- `VabRefresh`
- `VabRouterView`
- `VabSearch`
- `VabSideBar`
- `VabTabs`
- `VabTheme`
## 抽取建议(最小闭包)
- 优先使用任务模板:`openspec-lite/tasks/extract-component.yaml`
- 若组件涉及 Layout/Theme先抽 `layouts``vab-theme`,再补 `store-settings``plugin-vab`
高耦合组件规格(机读):
- `vab-app-main``openspec-lite/modules/vab-app-main.yaml`
- `vab-avatar``openspec-lite/modules/vab-avatar.yaml`
- `vab-breadcrumb``openspec-lite/modules/vab-breadcrumb.yaml`
- `vab-card``openspec-lite/modules/vab-card.yaml`
- `vab-colorful-card``openspec-lite/modules/vab-colorful-card.yaml`
- `vab-column-bar``openspec-lite/modules/vab-column-bar.yaml`
- `vab-router-view``openspec-lite/modules/vab-router-view.yaml`
- `vab-error-log``openspec-lite/modules/vab-error-log.yaml`
- `vab-fold``openspec-lite/modules/vab-fold.yaml`
- `vab-query-form``openspec-lite/modules/vab-query-form.yaml`
- `vab-refresh``openspec-lite/modules/vab-refresh.yaml`
- `vab-search``openspec-lite/modules/vab-search.yaml`
- `vab-lock``openspec-lite/modules/vab-lock.yaml`
- `vab-notice``openspec-lite/modules/vab-notice.yaml`
- `vab-logo``openspec-lite/modules/vab-logo.yaml`
- `vab-nav``openspec-lite/modules/vab-nav.yaml`
- `vab-language``openspec-lite/modules/vab-language.yaml`
- `vab-full-screen``openspec-lite/modules/vab-full-screen.yaml`
- `vab-footer``openspec-lite/modules/vab-footer.yaml`
- `vab-link``openspec-lite/modules/vab-link.yaml`
## 快速定位grep/语义检索)
- `library/components/<VabName>/index.vue`
- `VabThemeDrawer` / `VabThemeSetting`
- `VabMenu` / `VabTabs` / `VabSideBar`(通常与路由/权限/store 强相关)

View File

@@ -0,0 +1,32 @@
# 14. Store 模块清单src/store/modules
> 目的:让 AI 明确“权限/路由/主题/标签页”等基础能力分别由哪个 store 提供,抽取时不遗漏。
## 模块列表(按仓库实际文件列出)
- `acl.ts`:角色/权限/admin配合 `hasPermission()`
- `errorLog.ts`:错误日志收集(配合 `library/plugins/errorLog.ts`
- `routes.ts`:路由模式/菜单路由设置(前端/后端路由切换)
- `settings.ts`:主题/布局/语言/折叠等全局配置(见 `12-Settings-Store.md`
- `tabs.ts`:标签页 visitedRoutes 管理
- `user.ts`:登录/用户信息/登出/重置(联动 acl/routes/tabs/settings
对应模块规格(机读):
- `access-control``openspec-lite/modules/access-control.yaml`(覆盖 acl + hasPermission + 指令)
- `store-errorlog``openspec-lite/modules/store-errorlog.yaml`
- `store-routes``openspec-lite/modules/store-routes.yaml`
- `store-settings``openspec-lite/modules/store-settings.yaml`
- `store-tabs``openspec-lite/modules/store-tabs.yaml`
- `store-user``openspec-lite/modules/store-user.yaml`
## 最小依赖闭包提示
- 权限链路:`acl.ts` + `src/utils/permission.ts` + `library/plugins/directive.ts`
- 路由链路:`routes.ts` + `src/router/*` + `src/utils/routes.ts` +(可选)`src/api/router.ts`
- 主题链路:`settings.ts` + `library/styles/variables/vab-*-variables.module.scss`
## 验收点smoke
- 能创建 Pinia 并正常读取 settings/acl/user 等 store
- `hasPermission()` 能按 acl 状态返回布尔值

View File

@@ -0,0 +1,115 @@
# 15. 代码段地图Snippet Map
> 目的:给后续 AI coding 的“最常用代码段”提供**稳定来源与检索方式**,直接指向文件/关键词。
## 初始化与自动加载
- `setupVab(app)``library/index.ts`
- 背景 SCSS 自动加载:`require.context('./styles/background', false, /\\.scss$/)`
- 插件自动加载:`require.context('./plugins', true, /\\.ts$/)` + `app.use(Plugins(key).default)`
## Theme主题
- 打开抽屉事件:`$pub('theme')``library/components/VabTheme/*`
- 随机换肤事件:`$pub('random-theme')`
- 主题变量注入:`useSettingsStore().updateTheme()``src/store/modules/settings.ts`
- scss module 来源:`@vab/styles/variables/vab-*-variables.module.scss`
## Plugins全局注入/事件总线/指令)
- 事件总线注入:`$pub/$sub/$unsub``library/plugins/vab.ts`
- 权限指令:`v-permissions``library/plugins/directive.ts`
- 权限判断:`hasPermission()``src/utils/permission.ts`
## IconsSVG
- SVG 自动加载:`require.context('.', true, /\\.svg$/)``src/icon/index.ts`
## Router/Routes
- 后端路由转换:`convertRouter()``src/utils/routes.ts`
- 路由模式切换:`authentication === 'all'``src/store/modules/routes.ts`
- 过滤可访问路由:`filterRoutes([...constantRoutes, ...routes], control)``src/store/modules/routes.ts`
- 重置路由:`resetRouter(accessRoutes)``src/store/modules/routes.ts` / `src/router`
## Router Permissions
- 路由守卫入口:`setupPermissions(router)``src/router/permissions.ts`
- 白名单/登录拦截开关:`routesWhiteList` / `loginInterception` / `authentication``src/router/permissions.ts` / `src/config`
- 更新标题:`document.title = getPageTitle(to.meta.title)``src/router/permissions.ts`
## Config
- 配置聚合入口:`module.exports = { ...cli, ...setting, ...theme, ...network }``src/config/index.js`
- 路由/登录关键开关:`authentication/loginInterception/routesWhiteList/supportVisit``src/config/setting.config.js`
- 菜单关键开关:`defaultOpeneds/uniqueOpened/openFirstMenu``src/config/setting.config.js`
- 网络请求关键开关:`baseURL/successCode/statusName/messageName/requestTimeout``src/config/net.config.js`
## Router View
- 刷新当前视图缓存:`$sub('reload-router-view', ...)``library/components/VabRouterView/index.vue`
## Menu
- 点击当前菜单刷新:`$pub('reload-router-view')``library/components/VabMenu/components/VabMenuItem.vue`
## Refresh
- 刷新按钮触发:`$pub('reload-router-view')``library/components/VabRefresh/index.vue`
## Search
- 打开搜索快捷键:`ctrlKey/metaKey + 'k'``library/components/VabSearch/index.vue`
- 历史记录 key`vab_search_history``library/components/VabSearch/index.vue`
## Lock
- 锁屏开关:`handleLock()` / `handleUnLock()``library/components/VabLock/index.vue`
- 直接操作侧边栏:`document.querySelector('.vab-side-bar')``library/components/VabLock/index.vue`
## Notice
- 拉取通知:`getList()``library/components/VabNotice/index.vue` / `src/api/notice.ts`
## Language
- 语言切换:`useI18n().locale` / `changeLanguage(``library/components/VabLanguage/index.vue` / `src/store/modules/settings.ts`
- 切换后更新标题:`getPageTitle(``library/components/VabLanguage/index.vue` / `src/utils/pageTitle.ts`
## FullScreen
- 全屏切换:`useFullscreen().toggle``library/components/VabFullScreen/index.vue`
## Footer
- 页脚标题来源:`settings.title``library/components/VabFooter/index.vue` / `src/store/modules/settings.ts`
## Nav/Breadcrumb
- 顶部导航聚合:`<vab-nav />``library/components/VabNav/index.vue`
- 面包屑生成:`handleMatched(``library/components/VabBreadcrumb/index.vue` / `src/utils/routes.ts`
## Column Bar
- Column 二级菜单:`partialRoutes` + `defaultOpeneds``library/components/VabColumnBar/index.vue` / `src/store/modules/routes.ts` / `src/config`
## Avatar/Logo
- 用户下拉退出:`case 'logout'` + `toLoginRoute(route.fullPath)``library/components/VabAvatar/index.vue` / `src/utils/routes.ts`
- Logo/Title 来源:`logo/title``library/components/VabLogo/index.vue` / `src/store/modules/settings.ts`
## Link/Fold/Card
- 外链/内链切换:`isExternal(props.to)``library/components/VabLink/index.vue` / `src/utils/validate.ts`
- 折叠按钮:`toggleCollapse``library/components/VabFold/index.vue` / `src/store/modules/settings.ts`
- Skeleton 卡片:`el-skeleton``library/components/VabCard/index.vue`
## User/Auth
- 登出重置闭包:`resetAll()``src/store/modules/user.ts`,联动 acl/routes/tabs/resetRouter/removeToken
## API/Request
- axios 实例与拦截器:`axios.create` / `instance.interceptors``src/utils/request.ts`
- 401/402/403 分支:`case 401` / `case 402` / `case 403``src/utils/request.ts`
- token 注入:`Authorization: Bearer``src/utils/request.ts`

View File

@@ -0,0 +1,76 @@
# 16. Config Key Mapsrc/config
> 目的:让 AI 在迁移/新项目开发时,明确“哪些行为由哪些 config key 控制”,并能快速定位 key 的定义与使用点。
## 聚合入口
- `src/config/index.js` 会把 4 份配置聚合导出:
- `cli.config.js`(构建/CLI 相关)
- `setting.config.js`(通用/登录/路由/菜单/缓存等)
- `theme.config.js`(主题与 UI 开关默认值)
- `net.config.js`(网络请求相关)
注意:`src/config/*` 可能会被 `vue.config.js` 在 Node 环境 `require()` 读取,因此配置文件应避免使用 `window/document`
## 高影响 keys按子系统分组
### 路由/权限/登录
- `authentication`:路由模式(`intelligence` 前端路由 / `all` 后端路由)
- `loginInterception`:是否开启登录拦截(影响 `setupPermissions` 行为)
- `routesWhiteList`:白名单路由(不校验 token
- `supportVisit`:游客模式
- `rolesControl`:是否按 `roles` 字段进行角色控制
- `isHashRouterMode`hash/history 模式相关逻辑(菜单里对 `_blank` 打开内部路由有分支)
- `publicPath`:路由/跳转时可能需要的 publicPath
### Token/存储
- `tokenName`token 字段名
- `tokenTableName`:存储 key 名
- `storage``localStorage/sessionStorage/cookie`
- `recordRoute`token 失效回到登录页时是否记录本次路由
### 页面标题
- `title`:系统标题(影响 `getPageTitle`/浏览器标题/雪花屏标题等)
- `titleSeparator`:标题分隔符
- `titleReverse`:标题是否反转
### 菜单/导航体验
- `uniqueOpened`:是否只保持一个子菜单展开
- `defaultOpeneds`:默认展开菜单 path 列表
- `openFirstMenu`:是否点击一级菜单默认开启二级菜单
- `debounce`:需要加 loading 层防重复提交的请求标识列表
- `keepAliveMaxNum`keep-alive 最大缓存数量
### Theme 默认值与开关theme.config.js
- 默认值:`layout/themeName/background/menuWidth/columnStyle/...`
- UI 开关:`showProgressBar/showTabs/showLanguage/showRefresh/showSearch/showTheme/showNotice/showFullScreen/showThemeSetting/showLock/...`
### 网络请求net.config.js
- `baseURL` / `contentType` / `requestTimeout`
- `successCode` / `statusName` / `messageName`
### 构建/CLIcli.config.js
- `devPort/outputDir/assetsDir/publicPath`
- `pwa/buildOptimize/noDebugger/lintOnSave`
## 常见使用点(快速定位)
- 路由守卫:`src/router/permissions.ts``authentication/loginInterception/routesWhiteList/supportVisit` + `showProgressBar`
- Router 定义:`src/router/index.ts``authentication/isHashRouterMode/publicPath`
- 菜单:`library/components/VabMenu/components/VabMenuItem.vue``isHashRouterMode`
- 路由 store`src/store/modules/routes.ts``authentication/rolesControl`
- 标题工具:`src/utils/pageTitle.ts``titleSeparator/titleReverse`
- token 工具:`src/utils/token.ts``storage/tokenTableName`
- request`src/utils/request.ts``baseURL/successCode/statusName/messageName/requestTimeout/contentType` 等)
## 迁移/复用提示(最小闭包)
-`router`/`request`/`menu` 等模块时,**优先把 `src/config/*` 一并带走**,避免 key 缺失导致行为变化。
- 如果目标项目要改 key 名或改配置来源(例如改成 `.env` 或远端配置),建议先在规格里写清“映射关系”和“验收点”。

View File

@@ -0,0 +1,54 @@
# AI 复用操作手册(轻量化)
> 目标:在“不改动现有代码”的前提下,用文档约束 AI 从本仓库抽取能力,并确保抽取结果可验证。
## A. 选模块(先确定要什么)
在开始任何代码生成/迁移前AI 必须先回答:
- 我要复用的能力类型:`layout | component | plugin | util | store | i18n | api | mock | config`
- 复用方式:`copy-snippet`(复制片段)或 `copy-module`(整目录)
- 目标项目构建工具:`Vue CLI` / `Vite` / 其他
> 推荐:优先 `copy-module`(减少遗漏依赖),再做裁剪。
## B. 定位入口(必须列出入口文件)
- 全局能力:`library/index.ts``setupVab`
- 初始化:`src/main.ts`
- 路由:`src/router/index.ts`
- 状态:`src/store/index.ts`
- i18n`src/i18n/index.ts`
- Mock`mock/index.js`
AI 输出中必须包含:入口文件列表 + 为什么需要它们。
## C. 最小闭包(必须列出依赖闭包)
AI 必须同时列出:
- 直接依赖import 的文件/包)
- 运行时依赖例如全局样式、icons、插件自动加载
- 类型依赖(`types/` 目录与 `/#`
- alias 依赖(`@``@vab``~``/#`
> 如果依赖闭包不清晰,禁止直接迁移;应先补规格(见 `openspec-lite/`)。
## D. 迁移后验收(必须可执行)
最低验收:
- `pnpm run serve` 能启动
- 页面可渲染
- 路由能跳转
- i18n/store 能注入
- Mock若启用能命中
## E. 输出格式(给 OpenSpec/AI 工具链用)
当 AI 完成一次抽取/复用任务时,输出必须包含:
- **变更文件清单**(新增/修改/删除)
- **复用模块清单**(从哪里来、被用在何处)
- **验收命令**lint/test/build/serve
- **风险说明**可能破坏的点alias、插件自动加载、生产 mock 等)

View File

@@ -0,0 +1,8 @@
# 已知陷阱与迁移雷区Pitfalls
- **生产环境禁调试**`src/App.vue` 使用 `disable-devtool`,可能影响某些测试/调试环境。
- **生产环境默认 Mock**`src/main.ts` 中存在“生产启用 mockXHR”的逻辑做真实项目发布时要确认策略。
- **配置入口**`vue.config.js` 通过 `require('./src/config')` 读取配置;`src/config/index.js` 会聚合导出多个子配置。
- **自动插件加载**`library/index.ts``require.context('./plugins', true, /\\.ts$/)` 全量加载;抽取模块时容易带入不需要依赖。
> 对应的约束与处理建议:见 [openspec-lite/project.yaml](openspec-lite/project.yaml)。

View File

@@ -0,0 +1,56 @@
# AI-CodingAI 取材与约束入口)
> 本目录是“轻量化模板库”形态下的 AI 指南:**不改动现有业务代码**,尽量用文档与规格约束引导 OpenSpec 开发模式的 AI 快速、准确地复用本仓库能力。
## 你应该从这里开始读
1. [00-Quick-Profile.md](00-Quick-Profile.md) —— 30 秒摘要栈、入口链路、Mock、alias
2. [01-Directory-Map.md](01-Directory-Map.md) —— 仓库地图(模块在哪、职责是什么)
3. [02-Boot-Sequence.md](02-Boot-Sequence.md) —— 初始化链路(`src/main.ts` / `setupVab`
4. [10-Theme-System.md](10-Theme-System.md) —— Theme 系统VabTheme + settings + 变量注入)
5. [11-Plugins-System.md](11-Plugins-System.md) —— Pluginsgp 注入/指令/错误捕获)
6. [12-Settings-Store.md](12-Settings-Store.md) —— Settings Store主题/布局等全局配置)
7. [13-Component-Inventory.md](13-Component-Inventory.md) —— 组件清单library/components
8. [14-Store-Modules.md](14-Store-Modules.md) —— Store 模块清单src/store/modules
9. [15-Snippet-Map.md](15-Snippet-Map.md) —— 代码段地图(常用片段稳定来源)
10. [16-Config-Keys.md](16-Config-Keys.md) —— Config keys 地图(高影响开关与使用点)
11. [AI-Reuse-Playbook.md](AI-Reuse-Playbook.md) —— AI 复用操作手册(最小闭包、迁移步骤、验收)
12. [Pitfalls.md](Pitfalls.md) —— 已知陷阱与迁移雷区
## OpenSpec-lite轻量规格
- [openspec-lite/project.yaml](openspec-lite/project.yaml) —— 项目级约束(技术栈/目录/禁止项/验收门槛)
- [openspec-lite/manifest.yaml](openspec-lite/manifest.yaml) —— 模块清单(供 AI 选模块与定位)
- [openspec-lite/tasks/](openspec-lite/tasks/) —— 任务模板AI 按模板输出文件与验收项)
- [openspec-lite/modules/](openspec-lite/modules/) —— 模块规格(按需逐步补全;先从高频模块开始)
推荐从这些高频模块规格开始:
- `setup-vab``openspec-lite/modules/setup-vab.yaml`
- `config-system``openspec-lite/modules/config-system.yaml`
- `api-system``openspec-lite/modules/api-system.yaml`
- `icons``openspec-lite/modules/icons.yaml`
- `styles``openspec-lite/modules/styles.yaml`
- `access-control``openspec-lite/modules/access-control.yaml`
- `layouts``openspec-lite/modules/layouts.yaml`
- `ui-components``openspec-lite/modules/ui-components.yaml`
- `store-settings``openspec-lite/modules/store-settings.yaml`
- `vab-theme``openspec-lite/modules/vab-theme.yaml`
- `plugin-vab``openspec-lite/modules/plugin-vab.yaml`
- `plop``openspec-lite/modules/plop.yaml`
- `plugin-directive``openspec-lite/modules/plugin-directive.yaml`
- `plugin-errorlog``openspec-lite/modules/plugin-errorlog.yaml`
- `plugin-support``openspec-lite/modules/plugin-support.yaml`
- `VabApp``openspec-lite/modules/vab-app.yaml`
- `VabMenu``openspec-lite/modules/vab-menu.yaml`
- `VabTabs``openspec-lite/modules/vab-tabs.yaml`
- `VabHeader``openspec-lite/modules/vab-header.yaml`
- `VabSideBar``openspec-lite/modules/vab-sidebar.yaml`
更多模块(例如 `store-user` / `store-routes` / `store-tabs` / `store-errorlog`)已收录在 `openspec-lite/manifest.yaml` 中,可按需从清单选取。
## 本目录的“轻量化原则”
- **不要求改代码**:所有约束优先通过文档/规格落地;如必须改代码,应先在规格里写明原因与影响面。
- **先可用,再完美**:优先把“模块定位、最小闭包、验收门槛”写清楚。
- **一切可检索**:每份文档都应包含明确关键词与入口文件路径,方便 AI 语义检索/grep。

View File

@@ -0,0 +1,40 @@
# 可供 AI 检索的关键锚点Search Anchors
> 这些关键词可用于语义检索或 grep。
- 入口:`createApp(App)``setupVab(app)``setupRouter(app).isReady()`
- setupVab`require.context('./plugins'``require.context('./styles/background'``app.component('VabIcon'``createHead()`
- Mock`setupMiddlewares: require('./mock')``mockjs``responseFake`
- Alias`alias``@vab``/#`
- i18n`createI18n({ legacy: false })``translate(`
- Store`createPinia()``useSettingsStore(pinia)`
- Routes Store`setRoutes(``filterRoutes(``resetRouter(`
- Router/Views`component: () => import('@/views/``constantRoutes``asyncRoutes``breadcrumbHidden``noColumn``isCustomSvg``meta.target``meta.badge``meta.dot`
- Router Guard`setupPermissions(``router.beforeEach``routesWhiteList``loginInterception``authentication``supportVisit``VabProgress.start()``document.title = getPageTitle`
- User Store`getUserInfo(``resetAll(``removeToken(`
- Tabs Store`visitedRoutes``noClosable`
- RouterView`reload-router-view``keepAliveNameList``<keep-alive :include=`
- Refresh`theme.showRefresh``$pub('reload-router-view')`
- Search`Ctrl+K``vab_search_history``flattenMenus(``teleport to="body"`
- Lock`theme.showLock``settings.lock``.vab-side-bar``handleUnLock`
- Menu`menuComponent``VabSubMenu``VabMenuItem``inject('$pub')``reload-router-view``isHashRouterMode``teleported=false`
- Notice`api/notice``getList()``theme.showNotice``notice-popover``清空消息成功`
- Language`theme.showLanguage``useI18n().locale``changeLanguage(``getPageTitle(`
- FullScreen`theme.showFullScreen``useFullscreen()``isFullscreen``toggle()`
- Footer`vab-footer``$base-padding``$base-border-color`
- Avatar`useUserStore()``toLoginRoute(``command="logout"``/setting/personalCenter`
- Breadcrumb`handleMatched(``breadcrumbHidden``el-breadcrumb-item`
- Nav`layout === 'comprehensive'``openFirstMenu``tabMenu.value.path``<vab-breadcrumb`
- ColumnBar`theme.layout === 'column'``route.meta.noColumn``partialRoutes``defaultOpeneds`
- Logo`settingsStore``logo``is-custom-svg``theme.layout`
- Link`isExternal(``rel: 'noopener'``router-link`
- Fold`toggleCollapse``collapse ? 'menu-unfold-line'`
- Card`el-skeleton``skeletonRows``onBeforeRouteLeave`
- Theme`updateTheme()``vab-*-variables.module.scss``$pub('theme')``$pub('random-theme')`
- Plugins`app.config.globalProperties``app.provide(``v-permissions``app.config.errorHandler`
- ACL`useAclStore``hasPermission(`
- Icons`require.context('.', true, /\\.svg$/)`
- Config`require('./src/config')``src/config/index.js`
- Config Keys`authentication``loginInterception``routesWhiteList``supportVisit``rolesControl``isHashRouterMode``defaultOpeneds``uniqueOpened``openFirstMenu``tokenTableName``storage``titleSeparator``titleReverse`
- API`src/utils/request.ts``axios.create``instance.interceptors``refreshToken``Authorization: Bearer`
- Plop`plop.setGenerator``plopfile.js``plop-templates/`

View File

@@ -0,0 +1,104 @@
# 最小验证Validation
在本仓库验证:
```powershell
pnpm i
pnpm run serve
```
迁移到新仓库后,至少验证:
- 首页可渲染Layout 正常)
- 路由跳转正常
- Pinia 与 i18n 可注入
- Mock 请求可命中(开发环境)
建议附加:
```powershell
pnpm run lint
pnpm run test:unit
pnpm run build
```
## 文档/清单对账(防止漏登记模块)
对账 `library/components/*` 是否都已登记到 `AI-Coding/openspec-lite/manifest.yaml`
```powershell
$repo = (Get-Location).Path;
$componentDirs = Get-ChildItem -LiteralPath "$repo\library\components" -Directory | Select-Object -ExpandProperty Name | Sort-Object;
$manifest = Get-Content -LiteralPath "$repo\AI-Coding\openspec-lite\manifest.yaml" -Raw;
$manifestComponents = [regex]::Matches($manifest,'library/components/(?<name>Vab[^/]+)/') | ForEach-Object { $_.Groups['name'].Value } | Sort-Object -Unique;
Compare-Object -ReferenceObject $componentDirs -DifferenceObject $manifestComponents
```
对账 `library/layouts/*` 子目录是否都被 `AI-Coding/openspec-lite/modules/layouts.yaml` 覆盖:
```powershell
$repo = (Get-Location).Path;
$layoutDirs = Get-ChildItem -LiteralPath "$repo\library\layouts" -Directory | Select-Object -ExpandProperty Name | Sort-Object;
$layoutsSpec = Get-Content -LiteralPath "$repo\AI-Coding\openspec-lite\modules\layouts.yaml" -Raw;
$specDirs = [regex]::Matches($layoutsSpec,'library/layouts/(?<name>VabLayout[^/]+)/') | ForEach-Object { $_.Groups['name'].Value } | Sort-Object -Unique;
Compare-Object -ReferenceObject $layoutDirs -DifferenceObject $specDirs
```
对账 `components.d.ts` 里自动导入的 `Vab*` 组件是否都被任一 module spec 覆盖(按源文件路径精确匹配):
```powershell
$repo = (Get-Location).Path;
$dtsPath = "$repo\library\build\vuePlugins\components.d.ts";
$specDir = "$repo\AI-Coding\openspec-lite\modules";
$dts = Get-Content -LiteralPath $dtsPath -Raw;
$specText = (Get-ChildItem -LiteralPath $specDir -Filter '*.yaml' | ForEach-Object { Get-Content -LiteralPath $_.FullName -Raw }) -join "`n---`n";
$imports = [regex]::Matches(
$dts,
"Vab[A-Za-z0-9_]+:\\s*typeof\\s+import\\('(?<p>[^']+)'\\)\\['default'\\]",
[System.Text.RegularExpressions.RegexOptions]::Multiline
) | ForEach-Object { $_.Groups['p'].Value } | Where-Object { $_ -like '*components*' } | ForEach-Object {
$p = $_;
$p = $p -replace "^\\./\\.\\./\\.\\./","";
$p = $p -replace "^\\./\\.\\./","";
$p = $p -replace "^\\./","";
if ($p -like 'components/*') { $p = "library/" + $p }
$p
} | Sort-Object -Unique;
$missing = foreach ($p in $imports) { if ($specText -notmatch [regex]::Escape($p)) { $p } };
if ($missing) { $missing } else { '(none)' }
```
对账 `src/router/index.ts` 引用的 `@/views/*.vue` 是否都存在,并列出未被路由引用的 views
```powershell
$repo = (Get-Location).Path;
$routerPath = "$repo\src\router\index.ts";
$viewsRoot = "$repo\src\views";
$router = Get-Content -LiteralPath $routerPath -Raw;
# 只提取“非注释行”中的 views 引用,避免把 // 注释的 demo 路由当成缺失文件
$routeViewRefs = [regex]::Matches(
$router,
"(?m)^(?!\\s*//).*@/views/(?<p>[^'\\\"\\)]+\\.vue)",
[System.Text.RegularExpressions.RegexOptions]::Multiline
) | ForEach-Object { $_.Groups['p'].Value } | Sort-Object -Unique;
$missingFiles = foreach ($p in $routeViewRefs) {
$abs = Join-Path $viewsRoot ($p -replace '/', '\\');
if (-not (Test-Path -LiteralPath $abs)) { "src/views/$p" }
};
$allViews = Get-ChildItem -LiteralPath $viewsRoot -Recurse -File -Filter '*.vue' | ForEach-Object {
$_.FullName.Substring($viewsRoot.Length + 1).Replace('\\','/')
} | Sort-Object -Unique;
$unreferenced = Compare-Object -ReferenceObject $allViews -DifferenceObject $routeViewRefs -PassThru | Where-Object { $_ -in $allViews } | Sort-Object;
'--- router references missing files ---';
if ($missingFiles) { $missingFiles } else { '(none)' };
'--- views not referenced by router ---';
if ($unreferenced) { $unreferenced | ForEach-Object { "src/views/$_" } } else { '(none)' };
```

View File

@@ -0,0 +1,414 @@
# OpenSpec-lite: 模块清单(可逐步补全)
# 目的:让 AI 在“选模块”阶段就能定位入口与主要依赖。
modules:
- id: boot
name: 应用入口与初始化
type: core
entrypoints:
- src/main.ts
- library/index.ts
keywords:
- createApp
- setupVab
- setupI18n
- setupStore
- setupRouter
- id: setup-vab
name: setupVablibrary/index.ts 自动加载/图标/样式/插件)
type: core
entrypoints:
- library/index.ts
- library/plugins/
- library/styles/
- src/icon/index.ts
keywords:
- require.context
- VabIcon
- createHead
- id: router
name: 路由与权限
type: core
entrypoints:
- src/router/index.ts
- src/router/permissions.ts
keywords:
- constantRoutes
- asyncRoutes
- meta
- id: store
name: Pinia 状态
type: core
entrypoints:
- src/store/index.ts
- src/store/modules
keywords:
- createPinia
- id: store-settings
name: Settings Store主题/布局等全局配置)
type: store
entrypoints:
- src/store/modules/settings.ts
- library/styles/variables/
keywords:
- updateTheme
- themeName
- menuWidth
- id: store-routes
name: Routes Store路由拦截/菜单路由设置)
type: store
entrypoints:
- src/store/modules/routes.ts
keywords:
- setRoutes
- resetRouter
- id: store-user
name: User Store登录/用户信息/登出)
type: store
entrypoints:
- src/store/modules/user.ts
keywords:
- getUserInfo
- resetAll
- id: store-tabs
name: Tabs StorevisitedRoutes
type: store
entrypoints:
- src/store/modules/tabs.ts
keywords:
- visitedRoutes
- noClosable
- id: store-errorlog
name: ErrorLog Store错误日志收集
type: store
entrypoints:
- src/store/modules/errorLog.ts
keywords:
- addErrorLog
- id: i18n
name: 国际化
type: core
entrypoints:
- src/i18n/index.ts
keywords:
- createI18n
- translate
- id: api-system
name: API 层src/api + request 封装)
type: core
entrypoints:
- src/api/
- src/utils/request.ts
keywords:
- axios
- interceptors
- refreshToken
- id: config-system
name: 配置系统src/config 聚合)
type: core
entrypoints:
- src/config/index.js
- src/config
keywords:
- cli.config
- theme.config
- net.config
- id: access-control
name: 访问控制ACL + hasPermission + v-permissions
type: core
entrypoints:
- src/store/modules/acl.ts
- src/utils/permission.ts
- library/plugins/directive.ts
keywords:
- hasPermission
- v-permissions
- id: mock
name: 本地 Mock
type: tooling
entrypoints:
- mock/index.js
- mock/controller
keywords:
- setupMiddlewares
- mockjs
- responseFake
- id: icons
name: SVG Iconssrc/icon
type: ui
entrypoints:
- src/icon/index.ts
- src/icon
keywords:
- require.context
- svg
- id: styles
name: 样式体系library/styles
type: ui
entrypoints:
- library/styles/vab.scss
- library/styles/variables
- library/styles/background
keywords:
- scss
- variables
- id: ui-components
name: Vab 组件库
type: ui
entrypoints:
- library/components/
keywords:
- Vab
- ElementPlus
- id: vab-app
name: VabApp
type: ui
entrypoints:
- library/components/VabApp/
- id: vab-app-main
name: VabAppMain
type: ui
entrypoints:
- library/components/VabAppMain/
- id: vab-avatar
name: VabAvatar
type: ui
entrypoints:
- library/components/VabAvatar/
- id: vab-breadcrumb
name: VabBreadcrumb
type: ui
entrypoints:
- library/components/VabBreadcrumb/
- id: vab-card
name: VabCard
type: ui
entrypoints:
- library/components/VabCard/
- id: vab-colorful-card
name: VabColorfulCard
type: ui
entrypoints:
- library/components/VabColorfulCard/
- id: vab-column-bar
name: VabColumnBar
type: ui
entrypoints:
- library/components/VabColumnBar/
- id: vab-fold
name: VabFold
type: ui
entrypoints:
- library/components/VabFold/
- id: vab-footer
name: VabFooter
type: ui
entrypoints:
- library/components/VabFooter/
- id: vab-full-screen
name: VabFullScreen
type: ui
entrypoints:
- library/components/VabFullScreen/
- id: vab-language
name: VabLanguage
type: ui
entrypoints:
- library/components/VabLanguage/
- id: vab-link
name: VabLink
type: ui
entrypoints:
- library/components/VabLink/
- id: vab-logo
name: VabLogo
type: ui
entrypoints:
- library/components/VabLogo/
- id: vab-router-view
name: VabRouterView
type: ui
entrypoints:
- library/components/VabRouterView/
- id: vab-query-form
name: VabQueryForm
type: ui
entrypoints:
- library/components/VabQueryForm/
- id: vab-error-log
name: VabErrorLog
type: ui
entrypoints:
- library/components/VabErrorLog/
- id: vab-menu
name: VabMenu
type: ui
entrypoints:
- library/components/VabMenu/
- id: vab-nav
name: VabNav
type: ui
entrypoints:
- library/components/VabNav/
- id: vab-tabs
name: VabTabs
type: ui
entrypoints:
- library/components/VabTabs/
- id: vab-refresh
name: VabRefresh
type: ui
entrypoints:
- library/components/VabRefresh/
- id: vab-search
name: VabSearch
type: ui
entrypoints:
- library/components/VabSearch/
- id: vab-lock
name: VabLock
type: ui
entrypoints:
- library/components/VabLock/
- id: vab-notice
name: VabNotice
type: ui
entrypoints:
- library/components/VabNotice/
- id: vab-header
name: VabHeader
type: ui
entrypoints:
- library/components/VabHeader/
- id: vab-sidebar
name: VabSideBar
type: ui
entrypoints:
- library/components/VabSideBar/
- id: layouts
name: 布局体系
type: ui
entrypoints:
- library/layouts/index.vue
- library/layouts/
keywords:
- Layout
- id: vab-theme
name: Theme 系统VabTheme
type: ui
entrypoints:
- library/components/VabTheme/
- src/store/modules/settings.ts
- library/plugins/vab.ts
keywords:
- theme
- updateTheme
- $pub
- id: plugins
name: Plugins全局注入/指令/错误处理)
type: core
entrypoints:
- library/plugins/
keywords:
- app.use
- globalProperties
- id: plugin-vab
name: plugin-vabgp + mitt 事件总线)
type: plugin
entrypoints:
- library/plugins/vab.ts
keywords:
- $pub
- $sub
- mitt
- id: plugin-directive
name: plugin-directivev-permissions
type: plugin
entrypoints:
- library/plugins/directive.ts
keywords:
- v-permissions
- hasPermission
- id: plugin-errorlog
name: plugin-errorlog全局错误捕获
type: plugin
entrypoints:
- library/plugins/errorLog.ts
keywords:
- errorHandler
- useErrorLogStore
- id: plugin-support
name: plugin-support构建信息/依赖检查)
type: plugin
entrypoints:
- library/plugins/support.ts
keywords:
- __APP_INFO__
- id: build
name: 构建扩展
type: tooling
entrypoints:
- vue.config.js
- library/build
keywords:
- chainWebpack
- createVuePlugin
- id: plop
name: Plop 代码生成器
type: tooling
entrypoints:
- plopfile.js
- plop-templates/
keywords:
- plop
- setGenerator

View File

@@ -0,0 +1,27 @@
# Module Specaccess-controlACL + hasPermission + v-permissions
module:
id: access-control
name: 访问控制(角色/权限/指令)
type: core
entrypoints:
- src/store/modules/acl.ts
- src/utils/permission.ts
- library/plugins/directive.ts
public_api:
concept:
- "useAclStore 保存 admin/role/permission"
- "hasPermission(target) 统一判断路由/按钮权限"
- "v-permissions 指令在模板侧消费 hasPermission"
dependency_closure:
runtime:
- "Pinia store 初始化src/store/index.ts"
acceptance:
- "acl 中 admin=true 时 hasPermission 永远为 true"
- "指令 v-permissions 可用且不报错(具体隐藏/移除行为以实现为准)"
pitfalls:
- "权限数据来源通常由 user.getUserInfo() 写入 acl抽取时需明确数据流"

View File

@@ -0,0 +1,34 @@
# Module Specapi-systemsrc/api + axios request 封装)
module:
id: api-system
name: API 层src/api 域拆分 + src/utils/request.ts
type: core
entrypoints:
- src/api/
- src/utils/request.ts
public_api:
concept:
- "src/api/<domain>.ts按业务域拆分 API 函数"
- "src/utils/request.tsaxios 实例 + 拦截器 + 统一错误处理 + token 注入"
dependency_closure:
runtime:
- "axiosinstance + interceptors"
- "qsx-www-form-urlencoded 序列化)"
- "store/usertoken 注入、401/402 时 resetAll / refresh token"
- "plugin-vabgp.$baseMessage / gp.$baseLoadingloading 与错误提示)"
- "plugin-errorlogneedErrorLog/addErrorLog请求异常入库"
- "router401/403 跳转"
- "configbaseURL/requestTimeout/contentType/successCode/statusName/messageName/debounce 等"
- "api/refreshToken402 刷新 token 重试队列"
acceptance:
- "正常接口返回 code=200 时返回 data"
- "401 跳转 /login 且 resetAll 执行"
- "402 触发 refreshToken 并重放队列请求"
pitfalls:
- "request.ts 强依赖 gp全局注入与 user store抽取到新项目需明确入口安装顺序"
- "successCode/statusName/messageName 等与后端协议强耦合,迁移时先在规格声明差异"

View File

@@ -0,0 +1,31 @@
# Module Specconfig-systemsrc/config配置聚合
module:
id: config-system
name: 配置系统src/config 聚合导出)
type: core
entrypoints:
- src/config/index.js
- src/config/cli.config.js
- src/config/setting.config.js
- src/config/theme.config.js
- src/config/net.config.js
public_api:
concept:
- "src/config/index.js 将 4 个子配置聚合导出cli/setting/theme/network"
- "部分配置会被 vue.config.js 以 Node 方式 require 读取,因此子配置文件应保持 Node 兼容(避免 window/document"
key_index:
- "authentication/loginInterception/routesWhiteList/supportVisit/rolesControl/isHashRouterMode"
- "tokenName/tokenTableName/storage/recordRoute"
- "title/titleSeparator/titleReverse"
- "defaultOpeneds/uniqueOpened/openFirstMenu"
- "layout/themeName/menuWidth/columnStyle/showProgressBar/showTabs/showTheme/showThemeSetting"
- "baseURL/contentType/requestTimeout/successCode/statusName/messageName"
acceptance:
- "运行构建/启动时vue.config.js require config 不报错"
pitfalls:
- "配置文件在 Node 侧执行:避免使用浏览器对象"

View File

@@ -0,0 +1,20 @@
# Module Speciconssrc/iconSVG 自动加载)
module:
id: icons
name: SVG Iconssrc/icon require.context 自动加载)
type: ui
entrypoints:
- src/icon/index.ts
- src/icon/*.svg
public_api:
concept:
- "通过 require.context 自动加载 src/icon 下的 svg构建期打包进 sprite/资源管线,取决于 webpack 配置)"
dependency_closure:
bundler:
- "webpack require.context"
acceptance:
- "启动后 svg 资源被打包且可引用(具体引用方式取决于项目现有 svg loader 配置)"

View File

@@ -0,0 +1,40 @@
# Module Speclayouts布局体系
module:
id: layouts
name: 布局体系Layout Shell + 多布局实现)
type: ui
entrypoints:
- library/layouts/index.vue
- library/layouts/VabLayoutVertical/
- library/layouts/VabLayoutHorizontal/
- library/layouts/VabLayoutCommon/
- library/layouts/VabLayoutComprehensive/
- library/layouts/VabLayoutFloat/
- library/layouts/VabLayoutColumn/
public_api:
concept:
- "通过 theme.layout 选择渲染的布局组件:<component :is=\"'vab-layout-' + theme.layout\" />"
usage_examples:
- "在 settings store 中设置 theme.layout 为 vertical/horizontal/...Layout 会动态切换"
dependency_closure:
runtime:
- "Pinia settings storesrc/store/modules/settingstheme/layout/collapse/device"
- "Element Plusel-backtop"
- "Theme 组件library/components/VabThemeVabThemeDrawer/VabThemeSetting"
- "事件总线注入library/plugins/vab.ts$pub/$sub/$unsubTheme 抽屉依赖该注入)"
styles:
- "library/styles/variables/variables.module.scss布局 SCSS 变量)"
- "library/styles/variables/vab-*-variables.module.scssTheme 注入 Element Plus CSS 变量)"
acceptance:
- "Layout 可渲染并不报错"
- "窗口宽度 < 992 时进入 mobile 模式并能折叠菜单watch/resize 生效)"
- "Theme 抽屉/设置入口存在时不报错(缺失 $pub/$sub 注入会导致 Theme 不工作)"
pitfalls:
- "Layout 通过 require.context 自动注册 layouts 子目录下的 .vue迁移到非 webpack 环境时需要等效能力或手动注册"
- "Layout 与 Theme 都依赖 webpack 能力require.context / 动态 require scss module抽取到非 webpack 构建器时需要等效替代方案"

View File

@@ -0,0 +1,21 @@
# Module Spec示例mock
module:
id: mock
name: 本地 MockdevServer 中间件)
entrypoints:
- mock/index.js
- mock/controller
public_api:
concept:
- "route object: { url, type, response }"
usage_examples:
- "在 mock/controller/<domain>.js 增加路由对象devServer 会自动注册"
acceptance:
- "启动开发服务器后,请求命中 mock 并返回 mockjs 数据"
pitfalls:
- "路由匹配会自动拼 baseURL 前缀(来自 src/config"

View File

@@ -0,0 +1,19 @@
# Module Specplop代码生成器
module:
id: plop
name: Plop 代码生成器view/curd/component/mock&api
type: tooling
entrypoints:
- plopfile.js
- plop-templates/
public_api:
concept:
- "通过 plop generators 生成页面、curd、组件以及 mock&api 框架代码"
acceptance:
- "执行 plop 命令可正常出现 generators 并生成文件"
pitfalls:
- "生成结果依赖仓库既有目录约定src/views、src/api、mock/controller 等);新项目需对齐目录或改模板"

View File

@@ -0,0 +1,24 @@
# Module Specplugin-directive自定义指令v-permissions
module:
id: plugin-directive
name: 自定义指令v-permissions 权限控制)
type: plugin
entrypoints:
- library/plugins/directive.ts
public_api:
concept:
- "注册 v-permissions 指令,用于按权限隐藏/禁用 UI"
dependency_closure:
runtime:
- "权限判断src/utils/permissionhasPermission"
- "路由/用户权限数据:通常来自 store/user 或 routes 权限模块(视实现而定)"
acceptance:
- "模板中存在 v-permissions 使用时不报错"
- "无权限时能按设计移除/隐藏元素(以 hasPermission 实现为准)"
pitfalls:
- "指令依赖 hasPermission 的语义;抽取到目标项目需同步其实现与权限数据来源"

View File

@@ -0,0 +1,24 @@
# Module Specplugin-errorlog全局错误捕获与上报 store
module:
id: plugin-errorlog
name: 错误日志插件app.config.errorHandler + store 收集)
type: plugin
entrypoints:
- library/plugins/errorLog.ts
public_api:
concept:
- "根据配置决定是否启用全局 errorHandler"
- "将错误写入 useErrorLogStore用于页面展示/上报)"
dependency_closure:
runtime:
- "Piniasrc/store/modules/errorLoguseErrorLogStore"
- "configsrc/config/errorLog或 src/config/index.js 聚合)"
acceptance:
- "启用后,运行时异常会进入 error log store"
pitfalls:
- "若 store 未初始化或模块缺失,会导致 errorHandler 内再次报错"

View File

@@ -0,0 +1,23 @@
# Module Specplugin-support生产环境信息/依赖检查)
module:
id: plugin-support
name: Support 插件(构建信息输出/依赖检查)
type: plugin
entrypoints:
- library/plugins/support.ts
public_api:
concept:
- "生产环境输出构建信息__APP_INFO__"
- "检查关键依赖是否存在(例如 vab-icons"
dependency_closure:
runtime:
- "__APP_INFO__ 全局常量(通常由构建注入)"
acceptance:
- "生产环境能按预期打印/校验,不影响运行"
pitfalls:
- "依赖检查失败可能影响全局能力(与 vab 插件的保护逻辑相关)"

View File

@@ -0,0 +1,29 @@
# Module Specplugin-vab全局能力注入 + 事件总线)
module:
id: plugin-vab
name: Vab 插件gp 全局方法 + mitt 事件总线)
type: plugin
entrypoints:
- library/plugins/vab.ts
public_api:
concept:
- "通过 app.provide + app.config.globalProperties 注入 gp$baseLoading/$baseMessage/$baseAlert/$baseConfirm/$baseNotify/$baseTableHeight/$pub/$sub/$unsub"
- "内部使用 mitt 作为事件总线实现 $pub/$sub/$unsub"
dependency_closure:
runtime:
- "Element PlusElLoading / ElMessage / ElMessageBox / ElNotification"
- "mitt"
- "lodash"
- "src/configloadingText/messageDuration"
types:
- "types/library.d.tsglobalPropertiesType"
acceptance:
- "安装插件后,可通过 inject('$pub')/this.$pub 发布事件"
- "$baseMessage/$baseLoading 能正常工作"
pitfalls:
- "生产环境存在授权/依赖检查逻辑,可能将 app.config.globalProperties 置空(不要在外部假设 gp 永远存在)"

View File

@@ -0,0 +1,37 @@
# Module Specrouter路由与权限守卫
module:
id: router
name: 路由与页面组织
entrypoints:
- src/router/index.ts
- src/router/permissions.ts
public_api:
exports:
- constantRoutes
- asyncRoutes
- setupPermissions(router)
usage_examples:
- "新增页面:在 src/views/<module>/ 添加 Vue 文件,并在 asyncRoutes 中挂载到 Layout children"
dependency_closure:
runtime:
- "routervue-routerbeforeEach/afterEach"
- "store-usertoken/getUserInfo/resetAll/setVirtualRoles"
- "store-routessetRoutes(authentication)"
- "store-settingstheme.showProgressBar"
- "configauthentication/loginInterception/routesWhiteList/supportVisit"
- "utils/pageTitlegetPageTitle(to.meta.title)"
- "utils/routestoLoginRoute"
- "nprogressVabProgress含 nprogress.css"
acceptance:
- "路由可跳转"
- "刷新后路由仍可恢复"
pitfalls:
- "如涉及权限/菜单,需同步 metatitle/icon/...);同时注意 routesWhiteList/loginInterception/authentication 等开关影响守卫逻辑"
- "permissions.ts 直接写 document.title若新项目改为 useHead 等方式需统一"

View File

@@ -0,0 +1,30 @@
# Module Specsetup-vablibrary/index.ts自动加载、图标、样式、插件
module:
id: setup-vab
name: setupVab(app)(自动加载 styles/background/plugins + 图标注册)
type: core
entrypoints:
- library/index.ts
public_api:
concept:
- "setupVab(app) 是本模板把 'library/' 能力接入应用的总入口"
- "它负责:加载 svg 图标、全局样式、注册图标组件、自动加载背景样式与 plugins"
dependency_closure:
runtime:
- "src/icon/index.tssvg require.context"
- "library/styles/vab.scss全局样式入口"
- "@vueuse/headcreateHead"
- "vab-iconsVabIcon 组件 + CSS"
- "@element-plus/icons-vue全量注册 ElementPlus 图标组件)"
bundler:
- "webpack require.contextbackground scss / plugins ts 自动加载"
acceptance:
- "调用 setupVab(app) 后VabIcon 可用、ElementPlus 图标组件可用"
- "plugins 自动 app.use 安装,$pub/$sub 等全局注入可用(由 plugin-vab 决定)"
pitfalls:
- "setupVab 依赖 require.context迁移到非 webpack 构建器需要替代实现(手动 import 或 glob"

View File

@@ -0,0 +1,23 @@
# Module Specstore-errorlog错误日志收集 store
module:
id: store-errorlog
name: ErrorLog Store错误日志收集
type: store
entrypoints:
- src/store/modules/errorLog.ts
public_api:
concept:
- "addErrorLog追加错误日志"
- "clearErrorLog清空错误日志"
dependency_closure:
runtime:
- "通常由 plugin-errorloglibrary/plugins/errorLog.ts与 request 异常写入触发"
acceptance:
- "触发 addErrorLog 后 errorLogs 可读取"
pitfalls:
- "若错误处理链路缺失plugin/request 未接入store 仍可用但不会自动产生数据"

View File

@@ -0,0 +1,28 @@
# Module Specstore-routes路由模式/菜单路由状态)
module:
id: store-routes
name: Routes Store路由拦截/菜单路由设置)
type: store
entrypoints:
- src/store/modules/routes.ts
public_api:
concept:
- "setRoutes(mode):根据 authentication/rolesControl 生成可访问路由并 resetRouter"
- "支持前端路由asyncRoutes与后端路由getList -> convertRouter两种模式"
dependency_closure:
runtime:
- "routersrc/routerasyncRoutes/constantRoutes/resetRouter"
- "utils/routesconvertRouter/filterRoutes"
- "api/routergetList后端路由模式"
- "configauthentication/rolesControl"
- "plugin-vabgp.$baseMessage后端路由格式异常提示"
acceptance:
- "前端路由模式下setRoutes() 后 routes 可用于菜单渲染"
- "后端路由模式下getList 返回 list 后可 convertRouter 并 resetRouter"
pitfalls:
- "后端路由 list 格式必须符合 convertRouter 预期;否则会提示错误"

View File

@@ -0,0 +1,36 @@
# Module Specstore-settings全局配置/主题/布局状态)
module:
id: store-settings
name: Settings Store主题/布局/语言/折叠等全局配置)
type: store
entrypoints:
- src/store/modules/settings.ts
public_api:
concept:
- "集中管理全局配置theme、device、collapse、language、lock、logo、title"
- "持久化localStoragetheme/collapse/language/..."
- "主题注入updateTheme() 动态加载 scss module 并写入 CSS 变量(--el-*"
usage_examples:
- "useSettingsStore().updateTheme() 在应用启动或主题变更后调用"
- "useSettingsStore().toggleCollapse() 控制侧边栏折叠"
dependency_closure:
runtime:
- "src/config默认 theme/layout/开关项等)"
- "@vueuse/coreuseCssVar如果项目通过 auto-import 或显式引入提供)"
bundler:
- "webpack dynamic requirerequire(`@vab/styles/variables/vab-${themeName}-variables.module.scss`)"
alias:
- "@ -> src"
- "@vab -> library"
acceptance:
- "切换 themeName 后 updateTheme() 能更新 Element Plus CSS 变量"
- "刷新后 theme/collapse/language 等能从 localStorage 恢复"
pitfalls:
- "updateTheme() 使用动态 require scss module非 webpack 构建需替代实现"
- "useCssVar 的来源依赖工程约定(若未自动注入,需要显式 import"

View File

@@ -0,0 +1,24 @@
# Module Specstore-tabs标签页 visitedRoutes
module:
id: store-tabs
name: Tabs StorevisitedRoutes 管理)
type: store
entrypoints:
- src/store/modules/tabs.ts
public_api:
concept:
- "addVisitedRoute/delVisitedRoute/delOthers/delLeft/delRight/delAll"
- "确保至少存在一个 noClosable tab默认第一个"
dependency_closure:
runtime:
- "router typesVabRouteRecord/#/router"
acceptance:
- "路由切换时 addVisitedRoute 可累积标签页"
- "关闭/关闭其它/左右/全部等操作不报错"
pitfalls:
- "对 meta 合并有特殊逻辑dynamicNewTab/noClosable迁移时避免改坏行为"

View File

@@ -0,0 +1,31 @@
# Module Specstore-user登录/用户信息/登出/重置)
module:
id: store-user
name: User Store登录/用户信息/登出/重置)
type: store
entrypoints:
- src/store/modules/user.ts
public_api:
concept:
- "login/socialLogin登录并 afterLogin通知、设置 token"
- "getUserInfo拉取 username/avatar/roles/permissions 并写入 acl"
- "logout/resetAll清空 token/acl/routes/tabs 并 resetRouter"
dependency_closure:
runtime:
- "api/userlogin/getUserInfo/logout/socialLogin"
- "utils/tokengetToken/setToken/removeToken"
- "configtokenName"
- "storeacl/routes/tabs/settings 联动"
- "routerresetRouter"
- "plugin-vabgp.$baseNotify/$baseMessage提示"
acceptance:
- "登录成功后 token 写入并能继续请求"
- "getUserInfo 后 acl 中 roles/permissions 生效"
- "logout 后 resetAll 清理完成且路由重置"
pitfalls:
- "logout 内含 location.reload迁移到新项目需确认是否保留该行为"

View File

@@ -0,0 +1,22 @@
# Module Specstyleslibrary/styles全局样式/变量/背景)
module:
id: styles
name: 样式体系(全局样式 + 变量 + 背景)
type: ui
entrypoints:
- library/styles/vab.scss
- library/styles/variables/
- library/styles/background/
public_api:
concept:
- "vab.scss 是全局样式入口normalize/transition/变量等聚合)"
- "variables 下含布局变量与 Theme 变量vab-*-variables.module.scss"
dependency_closure:
bundler:
- "scss/sass loader由 Vue CLI 提供)"
acceptance:
- "引入 vab.scss 后基础样式生效,不影响 Element Plus"

View File

@@ -0,0 +1,27 @@
# Module Specui-componentsVab 组件库总览)
module:
id: ui-components
name: Vab 组件库library/components/Vab*
type: ui
entrypoints:
- library/components/
public_api:
concept:
- "每个组件目录对应一个 Vab* 组件族;复用优先按目录整包搬运"
dependency_closure:
runtime:
- "Element Plus大量 el-* 依赖)"
- "iconsvab-icons 与 @element-plus/icons-vue常通过 setupVab 全局注册)"
- "全局样式library/styles/vab.scss"
alias:
- "@ -> src"
- "@vab -> library"
acceptance:
- "目标项目能渲染组件(至少 smoke render"
pitfalls:
- "部分组件可能依赖路由、store、权限指令等全局插件抽取前必须列出依赖闭包"

View File

@@ -0,0 +1,27 @@
# Module Specvab-app-main主内容区联动 routes store
module:
id: vab-app-main
name: VabAppMain主内容区
type: ui
entrypoints:
- library/components/VabAppMain/index.vue
public_api:
concept:
- "监听 route 变化,更新 routes store 的 tab/activeMenu"
- "渲染 vab-router-view + vab-footer"
dependency_closure:
runtime:
- "vue-routeruseRoute"
- "store-routestab/activeMenu"
- "utils/routeshandleActivePath"
- "组件依赖VabRouterView、VabFooter需同时可用/注册)"
acceptance:
- "路由变化时 activeMenu.data 更新为当前激活路径"
- "主内容区能渲染 router-view 与 footer"
pitfalls:
- "tab 使用 route.matched[0].name若路由层级/匹配为空需要在目标项目确认兼容"

View File

@@ -0,0 +1,21 @@
# Module SpecVabApp
module:
id: vab-app
name: VabApp应用壳/全局容器)
type: ui
entrypoints:
- library/components/VabApp/index.vue
- library/components/VabApp/
usage_examples:
- "App 根组件中使用 <vab-app /> 作为应用容器"
dependency_closure:
runtime:
- "可能依赖 router-view 与 Element Plus ConfigProvider由 VabApp 内部决定)"
- "可能依赖 pwa / i18n / route meta"
acceptance:
- "渲染不报错"
- "路由切换正常(若内部包含 router-view"

View File

@@ -0,0 +1,28 @@
# Module Specvab-avatar用户头像下拉
module:
id: vab-avatar
name: VabAvatar用户头像/用户名下拉)
type: ui
entrypoints:
- library/components/VabAvatar/index.vue
public_api:
concept:
- "右上角用户头像下拉:个人中心/外链/退出登录,并在退出后跳转到登录页(携带回跳参数)"
dependency_closure:
runtime:
- "store-useravatar/username/logout()"
- "vue-routeruseRoute/useRouter"
- "utils/routestoLoginRoute(fullPath)"
- "i18ntranslate()"
- "Element Plusel-dropdown/el-dropdown-menu/el-dropdown-item/el-avatar"
- "VabIcon"
acceptance:
- "下拉可见时箭头激活态切换"
- "点击退出登录会调用 userStore.logout() 并跳转 toLoginRoute(route.fullPath)"
pitfalls:
- "依赖 userStore 提供 avatar/username新项目需保证字段一致"

View File

@@ -0,0 +1,28 @@
# Module Specvab-breadcrumb面包屑
module:
id: vab-breadcrumb
name: VabBreadcrumb面包屑
type: ui
entrypoints:
- library/components/VabBreadcrumb/index.vue
public_api:
concept:
- "根据 routesStore.getRoutes + 当前 route.path 生成面包屑,并支持 meta.icon/meta.isCustomSvg"
dependency_closure:
runtime:
- "store-routesgetRoutes"
- "vue-routeruseRoute"
- "utils/routeshandleMatched(routes, path)"
- "i18ntranslate()"
- "Element Plusel-breadcrumb/el-breadcrumb-item"
- "VabIcon"
acceptance:
- "meta.breadcrumbHidden=true 的路由不出现在面包屑"
- "每个 crumb 的跳转目标使用 item.redirect若存在"
pitfalls:
- "依赖后端路由结构与 meta 字段title/icon/isCustomSvg"

View File

@@ -0,0 +1,25 @@
# Module Specvab-card卡片封装 + Skeleton
module:
id: vab-card
name: VabCard卡片封装
type: ui
entrypoints:
- library/components/VabCard/index.vue
public_api:
concept:
- "对 el-card 的轻封装header slot/prop + 可选 skeleton loading默认 500ms 结束)"
dependency_closure:
runtime:
- "Element Plusel-card/el-skeleton"
- "vue-routeronBeforeRouteLeave清理定时器"
- "SCSS$base-transition"
acceptance:
- "skeleton=true 时先显示 skeleton再渲染默认 slot"
- "路由离开时清理 timer"
pitfalls:
- "skeletonRows 注释提示:显示数量可能比传入多 1Element Plus 行为)"

View File

@@ -0,0 +1,24 @@
# Module Specvab-colorful-card渐变卡片
module:
id: vab-colorful-card
name: VabColorfulCard渐变卡片
type: ui
entrypoints:
- library/components/VabColorfulCard/index.vue
public_api:
concept:
- "基于 el-card 的渐变背景卡片:支持 header 标题与右上角 icon"
dependency_closure:
runtime:
- "Element Plusel-card"
- "VabIcon可选"
acceptance:
- "传入 colorFrom/colorTo 时背景为 linear-gradient"
- "传入 icon 时显示 vab-icon"
pitfalls:
- "colorFrom/colorTo 需为合法 CSS color 字符串"

View File

@@ -0,0 +1,31 @@
# Module Specvab-column-bar列式布局左侧 Tab + 二级菜单)
module:
id: vab-column-bar
name: VabColumnBarColumn 布局列栏)
type: ui
entrypoints:
- library/components/VabColumnBar/index.vue
public_api:
concept:
- "Column 布局专用:左侧 tabs 切换顶级菜单,右侧 el-menu 渲染 partialRoutes二级菜单"
dependency_closure:
runtime:
- "store-settingstheme(layout/columnStyle)/collapse + foldSideBar/openSideBar"
- "store-routestab/tabMenu/activeMenu/routes/partialRoutes"
- "configdefaultOpeneds/openFirstMenu/uniqueOpened"
- "vue-routeruseRoute/useRouter"
- "utils/validateisExternal"
- "i18ntranslate()"
- "styles@vab/styles/variables/variables.module.scsscolumn-second-menu-background 等)"
- "Element Plusel-scrollbar/el-tabs/el-tab-pane/el-menu/el-divider"
- "VabLogo/VabMenu/VabIcon"
acceptance:
- "theme.layout==='column' 时可用route.meta.noColumn=true 时会自动折叠侧边栏并隐藏 fold-unfold"
- "点击 tab若 tabMenu.path 为外链则 window.open否则openFirstMenu=true跳转到 redirect 或自身"
pitfalls:
- "直接操作 DOMdocument.querySelector('.fold-unfold') 修改 style新项目结构不同需适配"

View File

@@ -0,0 +1,28 @@
# Module Specvab-error-log错误日志展示入口
module:
id: vab-error-log
name: VabErrorLog错误日志展示
type: ui
entrypoints:
- library/components/VabErrorLog/index.vue
public_api:
concept:
- "展示 errorLogs 数量徽标,点击打开弹窗列表"
- "提供清空日志入口clearErrorLog"
dependency_closure:
runtime:
- "store-errorloguseErrorLogStoreerrorLogs/clearErrorLog"
- "Element Plusel-badge/el-dialog/el-table/el-tag/el-popover/el-button"
- "VabIcon全局组件由 setup-vab 注册)"
related_modules:
- "plugin-errorlog负责把运行时错误写入 store否则列表为空"
acceptance:
- "errorLogs.length > 0 时显示徽标并可打开弹窗"
- "点击 '暂不显示' 能清空 store"
pitfalls:
- "仅负责展示;日志产生依赖 plugin/request 链路"

View File

@@ -0,0 +1,20 @@
# Module Specvab-fold折叠按钮
module:
id: vab-fold
name: VabFold侧边栏折叠/展开)
type: ui
entrypoints:
- library/components/VabFold/index.vue
public_api:
concept:
- "根据 settings.collapse 展示不同图标,并触发 settings.toggleCollapse()"
dependency_closure:
runtime:
- "store-settingscollapse/toggleCollapse"
- "VabIcon"
acceptance:
- "点击后触发 toggleCollapse 并切换图标"

View File

@@ -0,0 +1,25 @@
# Module Specvab-footer页脚
module:
id: vab-footer
name: VabFooter页脚
type: ui
entrypoints:
- library/components/VabFooter/index.vue
public_api:
concept:
- "展示年份与站点 title来自 settings store"
dependency_closure:
runtime:
- "store-settingstitle"
- "VabIcon"
styles:
- "SCSS 变量:$base-padding / $base-border-color来自 styles 模块)"
acceptance:
- "渲染后能显示年份与 title"
pitfalls:
- "样式依赖全局 SCSS 变量;目标项目缺失变量会导致样式编译失败"

View File

@@ -0,0 +1,24 @@
# Module Specvab-full-screen全屏切换
module:
id: vab-full-screen
name: VabFullScreen全屏切换
type: ui
entrypoints:
- library/components/VabFullScreen/index.vue
public_api:
concept:
- "点击图标切换全屏状态useFullscreen().toggle"
dependency_closure:
runtime:
- "@vueuse/coreuseFullscreen若项目通过 auto-import 或显式引入提供)"
- "store-settingstheme.showFullScreen"
- "VabIcon"
acceptance:
- "theme.showFullScreen=true 时显示图标,点击可进入/退出全屏"
pitfalls:
- "useFullscreen 的来源依赖工程约定(自动导入 vs 显式 import"

View File

@@ -0,0 +1,21 @@
# Module SpecVabHeader
module:
id: vab-header
name: VabHeader头部导航
type: ui
entrypoints:
- library/components/VabHeader/index.vue
- library/components/VabHeader/
usage_examples:
- "布局组件中使用 VabHeader承载用户信息/语言切换/全屏/刷新等入口"
dependency_closure:
runtime:
- "可能依赖 settings storefixedHeader/showTabs 等)"
- "可能依赖 i18n、router"
acceptance:
- "渲染不报错"
- "常用操作(如全屏/刷新/语言切换)不崩溃(若组件支持)"

View File

@@ -0,0 +1,28 @@
# Module Specvab-language语言切换
module:
id: vab-language
name: VabLanguage语言切换
type: ui
entrypoints:
- library/components/VabLanguage/index.vue
public_api:
concept:
- "通过下拉菜单切换语言:更新 settings.language + i18n locale + document.title"
dependency_closure:
runtime:
- "store-settingstheme.showLanguage / changeLanguage(language)"
- "vue-i18nuseI18n().locale"
- "vue-routeruseRoute读取 route.meta.title"
- "utils/pageTitlegetPageTitle"
- "Element Plusel-dropdown/el-dropdown-menu/el-dropdown-item"
- "VabIcon"
acceptance:
- "theme.showLanguage=true 时显示入口"
- "切换后 settings.language 与 i18n locale 同步更新"
pitfalls:
- "document.title 依赖 route.meta.title目标项目若 meta.title 缺失需适配"

View File

@@ -0,0 +1,21 @@
# Module Specvab-link智能链接
module:
id: vab-link
name: VabLink外链/内链统一)
type: ui
entrypoints:
- library/components/VabLink/index.vue
public_api:
concept:
- "根据 isExternal(to) 自动选择渲染 a 或 router-link"
dependency_closure:
runtime:
- "utils/validateisExternal"
- "vue-routerrouter-link"
acceptance:
- "外链target=_blank + rel=noopener"
- "内链:透传 to 给 router-link"

View File

@@ -0,0 +1,29 @@
# Module Specvab-lock锁屏/解锁)
module:
id: vab-lock
name: VabLock屏幕锁
type: ui
entrypoints:
- library/components/VabLock/index.vue
public_api:
concept:
- "点击锁屏图标将 settings.lock 置为 true并隐藏侧边栏 DOM"
- "解锁通过表单校验后将 settings.lock 置为 false并恢复侧边栏"
dependency_closure:
runtime:
- "store-settingstheme.showLock / lock / title / handleLock / handleUnLock"
- "store-useravatar"
- "i18ntranslate"
- "Element Plusel-avatar/el-form/el-form-item/el-input/el-button"
- "浏览器 DOMdocument.querySelector('.vab-side-bar')(直接改 style"
acceptance:
- "theme.showLock=true 时显示锁图标;点击后 lock=true 并出现锁屏层"
- "解锁成功后 lock=false页面恢复"
pitfalls:
- "组件内密码校验为固定值(示例逻辑);迁移到新项目需确认是否替换为真实策略"
- "直接操作 '.vab-side-bar' DOM若目标项目侧边栏类名不同需要适配"

View File

@@ -0,0 +1,26 @@
# Module Specvab-logoLogo + Title
module:
id: vab-logo
name: VabLogoLogo/标题)
type: ui
entrypoints:
- library/components/VabLogo/index.vue
public_api:
concept:
- "读取 settings.logo/settings.title并根据 theme.layout 渲染不同样式的 logo 区域"
dependency_closure:
runtime:
- "store-settingstheme/layout + logo + title"
- "vue-routerrouter-link"
- "VabIcon自定义 svgis-custom-svg"
- "SCSS$base-header-height/$base-logo-height/$base-title-color 等"
acceptance:
- "logo 存在时使用 vab-icon 渲染自定义 svg"
- "theme.layout==='horizontal' 时标题可隐藏hidden-xs-only"
pitfalls:
- "Column 布局会固定定位 logo依赖左侧菜单宽度相关变量"

View File

@@ -0,0 +1,39 @@
# Module SpecVabMenu
module:
id: vab-menu
name: VabMenu菜单体系
type: ui
entrypoints:
- library/components/VabMenu/index.vue
- library/components/VabMenu/components/VabMenuItem.vue
- library/components/VabMenu/components/VabSubMenu.vue
public_api:
concept:
- "递归渲染菜单VabMenu 根据子路由可见性选择渲染 VabSubMenu 或 VabMenuItem"
- "点击菜单:根据 meta.target/_blank、外链/内链、同路由刷新等逻辑进行跳转或触发 reload"
usage_examples:
- "布局组件中引入 VabMenu配合路由 meta 与权限渲染导航"
dependency_closure:
runtime:
- "vue-routeruseRoute/useRouter跳转/判断当前路由)"
- "store-settingscollapse/device/theme(layout) + foldSideBar移动端点击收起"
- "plugin-vabinject('$pub')(同路由点击触发 $pub('reload-router-view')"
- "configisHashRouterModehash 模式下 _blank 打开内部路由)"
- "utils/validateisExternal外链判断"
- "i18ntranslate菜单 title"
- "Element Plusel-menu-item/el-sub-menu/el-tag"
- "VabIcon"
acceptance:
- "item.children 中存在可见子路由时渲染 VabSubMenu否则渲染 VabMenuItem"
- "meta.target === '_blank' 时按外链/内链规则在新窗口打开"
- "点击当前已激活路由时触发 $pub('reload-router-view')"
pitfalls:
- "组件内部使用 webpack require.context 自动注册子组件;迁移到非 webpack 构建器需等效替代"
- "Element Plus 关于 teleported 的历史兼容问题:弹层渲染到 body 下时需要全局样式配合(见 VabMenu/index.vue 注释)"
- "如果菜单权限依赖 ACL/指令v-permissions/hasPermission迁移时必须把相关依赖一起带走"

View File

@@ -0,0 +1,29 @@
# Module Specvab-nav顶部导航条聚合
module:
id: vab-nav
name: VabNav顶部导航条
type: ui
entrypoints:
- library/components/VabNav/index.vue
public_api:
concept:
- "顶部导航聚合左侧Fold + Tabs/Breadcrumb右侧ErrorLog/Lock/Search/Notice/FullScreen/Language/Theme/Refresh/Avatar"
dependency_closure:
runtime:
- "store-routestab/tabMenu/routes"
- "vue-routeruseRouter"
- "utils/validateisExternal"
- "configopenFirstMenu"
- "i18ntranslate()"
- "Element Plusel-row/el-col/el-tabs/el-tab-pane"
- "ComponentsVabFold/VabBreadcrumb/VabErrorLog/VabLock/VabSearch/VabNotice/VabFullScreen/VabLanguage/VabTheme/VabRefresh/VabAvatar"
acceptance:
- "layout='comprehensive' 时显示顶部 tabs否则显示面包屑hidden-xs-only"
- "点击 tab外链 window.open否则openFirstMenu=true跳 redirect 或自身"
pitfalls:
- "强依赖多组件与 routesStore 输出结构;抽取时必须把依赖组件闭包一起带走"

View File

@@ -0,0 +1,31 @@
# Module Specvab-notice消息中心
module:
id: vab-notice
name: VabNotice消息中心/通知)
type: ui
entrypoints:
- library/components/VabNotice/index.vue
public_api:
concept:
- "显示通知 badge弹出 popover + tabs 展示通知/邮件"
- "从 api/notice.getList 拉取数据并计算 badge"
- "提供清空消息入口(仅清空前端列表与 badge并提示"
dependency_closure:
runtime:
- "store-settingstheme.showNotice"
- "api/noticegetList"
- "plugin-vab$baseMessage清空提示通过 inject 获取)"
- "i18ntranslate"
- "Element Plusel-badge/el-popover/el-tabs/el-tab-pane/el-scrollbar/el-avatar/el-button"
- "VabIcon"
acceptance:
- "theme.showNotice=true 时显示通知入口与 badge"
- "点击/切换 tab 会触发 fetchData 更新列表"
pitfalls:
- "数据协议依赖 notice.getList 的返回结构list/total"
- "清空仅影响前端状态,不等价于后端已读/删除"

View File

@@ -0,0 +1,29 @@
# Module Specvab-query-form查询表单布局容器
module:
id: vab-query-form
name: VabQueryForm查询条件容器
type: ui
entrypoints:
- library/components/VabQueryForm/index.vue
- library/components/VabQueryForm/components/VabQueryFormTopPanel.vue
- library/components/VabQueryForm/components/VabQueryFormBottomPanel.vue
- library/components/VabQueryForm/components/VabQueryFormLeftPanel.vue
- library/components/VabQueryForm/components/VabQueryFormRightPanel.vue
public_api:
concept:
- "基于 Element Plus el-row 的 slot 容器,用于统一查询表单布局与间距"
dependency_closure:
runtime:
- "Element Plusel-row"
styles:
- "SCSS 变量:$base-input-height / $base-margin来自全局样式变量体系见 styles 模块)"
acceptance:
- "作为容器包裹 el-form-item/el-button 时布局与间距符合预期"
pitfalls:
- "样式依赖全局 SCSS 变量;目标项目若未引入对应变量会导致样式编译失败"

View File

@@ -0,0 +1,25 @@
# Module Specvab-refresh刷新当前路由视图
module:
id: vab-refresh
name: VabRefresh刷新按钮
type: ui
entrypoints:
- library/components/VabRefresh/index.vue
public_api:
concept:
- "点击后通过事件总线发布 reload-router-view刷新当前 router-view 缓存"
dependency_closure:
runtime:
- "store-settingstheme.showRefresh是否显示按钮"
- "plugin-vab$pub发布事件"
related_modules:
- "vab-router-view订阅并处理 reload-router-view"
acceptance:
- "theme.showRefresh=true 时显示图标,点击触发 $pub('reload-router-view')"
pitfalls:
- "未安装 plugin-vab 或未接入 vab-router-view 时,点击不会产生效果"

View File

@@ -0,0 +1,31 @@
# Module Specvab-router-view路由视图壳keep-alive + 过渡 + reload 事件)
module:
id: vab-router-view
name: VabRouterViewrouter-view + keep-alive + reload
type: ui
entrypoints:
- library/components/VabRouterView/index.vue
public_api:
concept:
- "统一承载页面 router-view提供 keep-alive include 列表与过渡动画"
- "监听事件总线reload-router-view用于刷新当前视图缓存"
dependency_closure:
runtime:
- "vue-routeruseRoute / <router-view>"
- "plugin-vab$sub/$unsub事件订阅"
- "store-settingstheme.showProgressBar / theme.showPageTransition"
- "store-tabsvisitedRoutes生成 keepAliveNameList"
- "utils/routeshandleActivePath生成 routerKey"
- "configkeepAliveMaxNum"
- "nprogress显示刷新进度条"
acceptance:
- "路由切换时 keep-alive include 列表随 visitedRoutes 更新"
- "$sub('reload-router-view') 触发后当前视图能被重新渲染routerKey 变更)"
pitfalls:
- "存在 get-code 事件并依赖组件的 __source 字段;不同构建/插件下可能不存在"
- "未安装 plugin-vab 时 $sub/$unsub 不存在reload/get-code 事件不会工作"

View File

@@ -0,0 +1,30 @@
# Module Specvab-search菜单搜索Ctrl/⌘+K
module:
id: vab-search
name: VabSearch菜单搜索
type: ui
entrypoints:
- library/components/VabSearch/index.vue
public_api:
concept:
- "通过 Ctrl/⌘+K 或点击图标打开搜索面板teleport 到 body"
- "从 routes store 的 getRoutes 平铺菜单项并模糊搜索"
- "维护本地搜索历史 localStorage(key=vab_search_history)"
dependency_closure:
runtime:
- "store-routesgetRoutes菜单路由来源"
- "vue-routeruseRouterrouter.push 内链跳转)"
- "浏览器 APIwindow.addEventListener('keydown'), navigator.userAgent, localStorage"
- "VabIcon搜索图标与历史删除图标"
acceptance:
- "Ctrl/⌘+K 可打开/关闭面板Escape 关闭)"
- "输入关键字能过滤菜单并 Enter 跳转"
- "搜索历史能写入/删除/清空"
pitfalls:
- "该组件包含较多样式与 DOM 交互teleport/fixed mask抽取到新项目需确保全局样式/层级不冲突"
- "菜单来源依赖 routes store 已完成 setRoutes否则列表为空"

View File

@@ -0,0 +1,20 @@
# Module SpecVabSideBar
module:
id: vab-sidebar
name: VabSideBar侧边栏容器
type: ui
entrypoints:
- library/components/VabSideBar/index.vue
- library/components/VabSideBar/
usage_examples:
- "在布局中使用 VabSideBar 包裹 VabMenu实现侧边导航"
dependency_closure:
runtime:
- "settings storecollapse/device 等"
- "Element Plus如内部使用 el-scrollbar 等)"
acceptance:
- "折叠状态切换后布局不崩溃"

View File

@@ -0,0 +1,21 @@
# Module SpecVabTabs
module:
id: vab-tabs
name: VabTabs多标签页/导航标签)
type: ui
entrypoints:
- library/components/VabTabs/index.vue
- library/components/VabTabs/
usage_examples:
- "布局头部或主区域放置 VabTabs展示已访问路由并支持关闭/切换"
dependency_closure:
runtime:
- "vue-router监听路由变化"
- "storetabs 状态(如果实现依赖 store 模块)"
acceptance:
- "访问多个路由后能出现多个 tab如功能支持"
- "切换/关闭 tab 不崩溃"

View File

@@ -0,0 +1,40 @@
# Module Specvab-theme主题系统入口与交互
module:
id: vab-theme
name: VabTheme主题配置入口/抽屉/设置面板)
type: ui
entrypoints:
- library/components/VabTheme/index.vue
- library/components/VabTheme/components/VabThemeDrawer.vue
- library/components/VabTheme/components/VabThemeSetting.vue
- library/components/VabTheme/components/
public_api:
concept:
- "VabTheme一个刷子图标入口用于触发打开主题抽屉Drawer"
- "VabThemeDrawer主题抽屉监听事件总线打开/随机主题,并调用 settings store 的 saveTheme/resetTheme/updateTheme"
- "VabThemeSetting右侧固定设置入口主题配置/随机换肤/购买源码/清理缓存),通过事件总线触发行为"
usage_examples:
- "点击 VabTheme 触发 $pub('theme') 打开抽屉"
- "点击 VabThemeSetting 的随机换肤触发 $pub('random-theme')"
dependency_closure:
runtime:
- "Pinia settings storesrc/store/modules/settingstheme.showTheme、saveTheme/resetTheme/updateTheme 等)"
- "事件总线/全局注入library/plugins/vab.ts$pub/$sub/$unsub/$baseLoading 等)"
- "i18n translatesrc/i18n/index.ts组件内调用 translate"
- "Element PlusDrawer/Radio/Select/Button 等"
styles:
- "主题变量library/styles/variables/vab-*-variables.module.scssupdateTheme() 动态注入 CSS 变量)"
acceptance:
- "页面渲染包含主题入口(刷子图标)"
- "触发 $pub('theme') 时抽屉能打开;关闭时不报错"
- "保存/重置主题后调用 updateTheme() 生效CSS 变量与 body class 变化)"
pitfalls:
- "Theme 依赖 $pub/$sub 注入;若未安装 vab 插件,事件不会触发"
- "settings.updateTheme() 依赖 webpack 的 require 动态引入 scss module迁移到非 webpack 环境需等效实现"
- "移动端(<992某些操作会触发 reload抽取时需确认期望行为"

View File

@@ -0,0 +1,64 @@
# OpenSpec-lite: 项目级规格(轻量版)
# 目的:用“可机读约束”引导 AI 在不改动现有代码的情况下复用资源。
project:
name: admin-plus-template
intent: "公司内部模板库/基础库(轻量化,优先文档约束)"
stack:
framework: "Vue 3"
build: "Vue CLI 5"
language: "TypeScript"
state: "Pinia"
router: "Vue Router"
ui: "Element Plus"
constraints:
no_code_changes_by_default: true
prefer_docs_over_refactor: true
extraction_style:
- "copy-module" # 优先整目录搬运再裁剪
- "copy-snippet" # 仅在模块过大或依赖不清晰时使用
required_output_sections:
- "changed_files" # 变更文件清单
- "extracted_modules" # 抽取模块清单(来源->目标)
- "dependency_closure" # 依赖闭包imports/运行时/类型/alias
- "acceptance_commands" # 验收命令
- "risks" # 风险说明
forbidden_by_default:
- "changing runtime behavior in production" # 禁止默认更改生产行为
- "introducing new global side effects" # 禁止新增全局副作用
- "deep-importing internal paths of modules" # 禁止消费者深层路径引用
acceptance:
minimum_commands:
- "pnpm run serve"
recommended_commands:
- "pnpm run lint"
- "pnpm run test:unit"
- "pnpm run build"
repository:
entrypoints:
- "src/main.ts"
- "library/index.ts"
- "src/router/index.ts"
- "src/store/index.ts"
- "src/i18n/index.ts"
- "mock/index.js"
module_roots:
ui_components_dir: "library/components"
layouts_dir: "library/layouts"
plugins_dir: "library/plugins"
styles_dir: "library/styles"
store_modules_dir: "src/store/modules"
api_dir: "src/api"
utils_dir: "src/utils"
config_dir: "src/config"
icons_dir: "src/icon"
notes:
- "配置读取来自 src/config/index.js被 vue.config.js require"
- "library/index.ts 存在插件自动全量加载;抽取时需显式列出依赖闭包"

View File

@@ -0,0 +1,25 @@
# Task Template: 新增 API + Mock轻量版
task:
id: add-api-and-mock
intent: "新增一个 API 调用函数,并同步补一个 Mock 路由(用于开发联调)"
inputs:
required:
- domain
- function_name
- method # get/post/...
- path # 例如 /router/getList
outputs:
files_to_change:
- "src/api/<domain>.ts"
- "mock/controller/<domain>.js"
rules:
- "API path 与 Mock path 必须一致"
- "Mock 路由对象必须包含 url/type/response"
acceptance:
- "开发环境请求能命中 mock"
- "API 函数能被页面调用且类型不报错(若涉及类型需补 types/"

View File

@@ -0,0 +1,28 @@
# Task Template: 新增页面 + 路由(轻量版)
# 目标:约束 AI 在本仓库(或迁移后的新仓库)新增页面时的输出与验收。
task:
id: add-page
intent: "新增一个页面,并把路由挂载到 Layout如需要同步 meta 供菜单/面包屑使用)"
inputs:
required:
- module # 例如 goods / userManagement
- page_name # 例如 list / detail
- route_path # 例如 /goods/list
- route_name # 例如 GoodsList
outputs:
files_to_change:
- "src/views/<module>/<page>.vue"
- "src/router/index.ts"
rules:
- "页面文件必须位于 src/views/<module>/ 下"
- "路由必须挂载到 asyncRoutes 的 Layout children除非明确说明是 constantRoutes"
- "如需要菜单展示,必须填写 meta.title如需要图标必须填写 meta.icon"
acceptance:
- "访问 route_path 能渲染页面"
- "刷新后仍可访问(路由可恢复)"
- "若配置 meta菜单/面包屑能展示正确标题"

View File

@@ -0,0 +1,37 @@
# Task Template: 抽取组件library/components/Vab*
task:
id: extract-component
intent: "从本仓库抽取一个或多个 Vab 组件到目标项目,确保依赖闭包完整"
inputs:
required:
- components # 例如 ["VabTabs", "VabMenu"]
- target_project_type
- extraction_style
scope:
base_dir: "library/components"
dependency_closure_checklist:
runtime:
- "Element Plus 组件是否使用el-*"
- "iconsvab-icons 与 @element-plus/icons-vue 是否需要"
- "全局样式library/styles/vab.scss 是否是前置依赖"
app_wiring:
- "是否依赖 setupVab 的全局注册VabIcon / 图标注册 / 插件自动加载)"
alias:
- "@ -> src"
- "@vab -> library"
outputs:
required_sections:
- changed_files
- extracted_modules
- dependency_closure
- acceptance_commands
- risks
acceptance:
- "目标项目可渲染组件"
- "关键交互可用(按组件规格中的验收点)"

View File

@@ -0,0 +1,44 @@
# Task Template: 抽取布局体系library/layouts
task:
id: extract-layout
intent: "从本仓库抽取布局体系到目标项目,最小闭包迁移,尽量不改动原仓库代码"
inputs:
required:
- target_project_type # vue-cli | vite | other
- extraction_style # copy-module | copy-snippet
scope:
entrypoints:
- library/layouts/index.vue
- library/layouts/VabLayoutVertical/
- library/layouts/VabLayoutHorizontal/
- library/layouts/VabLayoutCommon/
- library/layouts/VabLayoutComprehensive/
- library/layouts/VabLayoutFloat/
- library/layouts/VabLayoutColumn/
dependency_closure_checklist:
runtime:
- "Element Plusel-backtop 等)"
- "Theme 组件library/components/VabTheme是否随闭包迁移"
- "事件总线注入library/plugins/vab.ts$pub/$sub/$unsub是否可用"
- "Pinia settings storesrc/store/modules/settingstheme/layout/collapse/device"
- "全局样式变量library/styles/variables/(布局 SCSS 使用的变量)"
- "Theme 变量library/styles/variables/vab-*-variables.module.scsssettings.updateTheme() 依赖)"
alias:
- "@ -> src"
- "@vab -> library"
outputs:
required_sections:
- changed_files
- extracted_modules
- dependency_closure
- acceptance_commands
- risks
acceptance:
- "Layout 能渲染"
- "切换移动端/桌面端时不崩溃resize/watch 逻辑生效)"

View File

@@ -0,0 +1,30 @@
# Task Template: 抽取/复用模块(轻量版)
task:
id: extract-module
intent: "从本仓库抽取模块到目标项目,尽量不改动原仓库代码"
inputs:
required:
- module_id
- target_project_type # vue-cli | vite | other
- extraction_style # copy-module | copy-snippet
outputs:
required_sections:
- changed_files
- extracted_modules
- dependency_closure
- acceptance_commands
- risks
procedure:
- step: "从 openspec-lite/manifest.yaml 选择 module_id 并列出 entrypoints"
- step: "读取入口文件,分析 import 依赖与运行时依赖样式、插件、types、alias"
- step: "按 extraction_style 抽取(优先 copy-module"
- step: "在目标项目补齐依赖package.json、alias、types include"
- step: "给出最小验收命令并说明风险"
acceptance:
- "目标项目可启动serve"
- "模块能力可用(根据 module_id 的验收点)"

View File

@@ -0,0 +1,35 @@
# Task Template: 抽取插件library/plugins/*
task:
id: extract-plugin
intent: "从本仓库抽取一个或多个插件到目标项目,确保注入点与依赖闭包完整"
inputs:
required:
- plugins # 例如 ["vab", "directive", "errorLog", "support"]
- target_project_type
- extraction_style
scope:
base_dir: "library/plugins"
dependency_closure_checklist:
runtime:
- "vabElement Plus 的 ElMessage/ElLoading/ElMessageBox/ElNotification 是否全局可用"
- "directivesrc/utils/permission 与权限数据来源是否齐全"
- "errorLogsrc/store/modules/errorLog 与 config/errorLog 是否齐全"
- "support__APP_INFO__ 注入方式是否一致"
wiring:
- "是否通过 setupVab(library/index.ts) 自动 app.use() 安装;若非自动,需要在入口手动 app.use()"
outputs:
required_sections:
- changed_files
- extracted_modules
- dependency_closure
- acceptance_commands
- risks
acceptance:
- "插件安装后,不影响应用启动"
- "涉及的注入能力/指令/错误捕获按模块规格验收"

View File

@@ -0,0 +1,41 @@
# Task Template: 抽取主题系统VabTheme + settings 主题闭包)
task:
id: extract-theme
intent: "从本仓库抽取 Theme 系统到目标项目,确保事件总线 + settings theme 闭包完整"
inputs:
required:
- target_project_type # vue-cli | vite | other
- extraction_style # copy-module | copy-snippet
scope:
entrypoints:
- library/components/VabTheme/
- src/store/modules/settings.ts
- library/plugins/vab.ts
- library/styles/variables/
dependency_closure_checklist:
runtime:
- "Pinia settings store 是否存在并已在入口初始化"
- "vab 插件是否安装($pub/$sub/$baseLoading 注入)"
- "i18n translate 是否可用"
- "Element Plus Drawer/表单控件是否可用"
bundler:
- "settings.updateTheme() 的 require('@vab/styles/variables/vab-*-variables.module.scss') 在目标构建器中是否可用"
alias:
- "@ -> src"
- "@vab -> library"
outputs:
required_sections:
- changed_files
- extracted_modules
- dependency_closure
- acceptance_commands
- risks
acceptance:
- "触发 $pub('theme') 能打开 Theme Drawer"
- "修改主题并保存后,刷新页面主题持久化且样式变量生效"

373
front-end/LICENSE Normal file
View File

@@ -0,0 +1,373 @@
Mozilla Public License Version 2.0
==================================
1. Definitions
--------------
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
1.3. "Contribution"
means Covered Software of a particular Contributor.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
1.5. "Incompatible With Secondary Licenses"
means
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
1.8. "License"
means this document.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
1.10. "Modifications"
means any of the following:
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
(b) any new file in Source Code Form that contains any Covered
Software.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
2. License Grants and Conditions
--------------------------------
2.1. Grants
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
2.2. Effective Date
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
2.3. Limitations on Grant Scope
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
(a) for any code that a Contributor has removed from Covered Software;
or
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
2.4. Subsequent Licenses
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
2.5. Representation
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
2.6. Fair Use
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
2.7. Conditions
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
3. Responsibilities
-------------------
3.1. Distribution of Source Form
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
3.2. Distribution of Executable Form
If You distribute Covered Software in Executable Form then:
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
3.3. Distribution of a Larger Work
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
3.4. Notices
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
3.5. Application of Additional Terms
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
5. Termination
--------------
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
8. Litigation
-------------
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
9. Miscellaneous
----------------
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
10. Versions of the License
---------------------------
10.1. New Versions
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
10.2. Effect of New Versions
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
10.3. Modified Versions
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
Exhibit A - Source Code Form License Notice
-------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
You may add additional accurate notices of copyright ownership.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

165
front-end/README.md Normal file
View File

@@ -0,0 +1,165 @@
# Admin PlusVue3 企业级开发模板)
面向公司项目的前端模板与基础库:内置 `Vue 3 + Vue CLI 5 + TypeScript + Pinia + Vue Router + Element Plus`,并集成 Mock、代码生成Plop、多套布局组件与常用工具链支持在此基础上快速裁剪与复用。
> 本仓库同时提供面向 AI 的结构说明与模块索引:见 [AI-Coding/README.md](AI-Coding/README.md)。
---
## 亮点
- **开箱即用**工程化配置齐全TS/ESLint/Prettier/Stylelint/Unit Test
- **可扩展的 UI/布局体系**`library/layouts/``library/components/` 内置多布局与业务型基础组件。
- **Mock 一体化**:开发环境通过 `devServer.setupMiddlewares` 自动挂载 `mock/` 路由。
- **现代依赖栈**`Element Plus` + `@element-plus/icons-vue`,并内置图标组件 `vab-icons`
- **可生成代码**:通过 `plop` 快速生成页面/CRUD/组件/mock&api。
---
## 环境要求
- Node.js建议 **16/18/20 LTS**(与 Vue CLI 5 兼容)
- 包管理器:推荐 `pnpm`(项目脚本也提供 `npm` 用法)
---
## 快速开始
### 1安装依赖
```powershell
cd d:\project\Web_Template_Vue3_Dev
pnpm i
```
如你使用 npm
```powershell
cd d:\project\Web_Template_Vue3_Dev
npm i
```
### 2启动开发环境
```powershell
pnpm run serve
```
### 3构建
```powershell
pnpm run build
```
### 4单元测试 / 代码质量
```powershell
pnpm run test:unit
pnpm run lint
pnpm run lint:eslint
pnpm run lint:prettier
pnpm run lint:stylelint
```
---
## 常用脚本scripts
来自 `package.json`
- **`serve`**:启动开发服务器(本地 Mock 会自动挂载)。
- **`build`**:生产构建。
- **`build:compress` / `compress`**:构建后压缩产物(`scripts/compress.js`)。
- **`build:website`**:站点构建(使用 `VAB_VARIABLE=website` + 压缩)。
- **`test:unit`**:单元测试。
- **`lint`**Vue CLI ESLint。
- **`lint:eslint` / `lint:prettier` / `lint:stylelint`**:更精细的格式化与风格修复。
- **`template`**:启动 `plop` 代码生成。
---
## 项目结构(速览)
> 更完整、可供 AI 检索复用的索引见 [AI-Coding/README.md](AI-Coding/README.md)。
```text
src/ 应用主代码(入口、路由、状态、国际化、业务页面)
library/ 模板基础库(全局样式、插件集合、构建扩展等)
library/components/ 可复用基础组件Vab* 体系)
library/layouts/ 多套布局(含主 Layout 入口)
mock/ 本地 Mock 服务devServer 中间件挂载)
types/ 全局类型声明与业务类型
tests/unit/ 单元测试
scripts/ 构建后处理脚本(如压缩)
public/ 静态资源与 HTML 模板
```
---
## 关键约定与入口
### 应用入口
- `src/main.ts`
- 创建应用并挂载:`createApp(App)`
- 初始化顺序:`setupVab``setupI18n``setupStore``setupRouter`
- 生产环境可自动启用 Mock`baseURL` 不是外链地址时(见 `src/main.ts` 的判断)
### 路由
- `src/router/index.ts`
- `constantRoutes`:如登录/注册/404 等基础路由
- `asyncRoutes`:业务路由(包含 `Layout` 作为壳)
### 状态管理
- `src/store/index.ts`Pinia 初始化与注入。
### 国际化
- `src/i18n/index.ts`
- `createI18n({ legacy:false })`
- 当前语言读取自 `useSettingsStore(pinia)`
### Mock
- `mock/index.js`
- 挂载到开发服务器中间件(在 `vue.config.js``devServer.setupMiddlewares`
- 基于 `mockjs` 返回数据,并支持文件变更热更新
---
## 别名Alias
来自 `vue.config.js` / `tsconfig.json`
- `@``src`
- `~` → 项目根目录
- `/#``types`
- `@vab``library`
- `@gp``library/plugins/vab`
---
## 代码生成Plop
项目提供 `plop` 生成器(见 `plopfile.js`
- `view`:页面
- `curd`CRUD
- `component`:组件
- `mock&api`Mock 与 API 片段
运行:
```powershell
pnpm run template
```
---
## 贡献与团队协作建议
- 建议以“业务模块”为单位在 `src/views/` 组织页面。
- API 按域拆分在 `src/api/`,与 `mock/controller/` 保持同名与路径一致,方便对照。
- 公共能力优先沉淀在 `library/`(全局插件/样式/构建扩展)与 `library/components/`(可视组件)。

Some files were not shown because too many files have changed in this diff Show More