Some checks failed
Web UI CI/CD / build-and-deploy (push) Failing after 46m41s
## 描述 将 `cleaning` 开发分支合并到 `master`。 主要改动包括: - 基础前端页面调整为初版设计 `cleaning` 分支中包含了多个开发过程的提交,本次合并计划 **使用 Squash 合并为一次提交**,以保持 `master` 分支历史清晰。 ## 类型 - [ ] Bug 修复(非破坏性修改) - [x] 新功能(非破坏性新增功能) - [ ] 破坏性修改(修改会影响现有功能) - [ ] 需要更新文档 - [x] 除非引入新的测试示例,否则不修改 `pnpm-lock.yaml` Reviewed-on: http://124.221.55.225:3000/XW-AIOT/aiot-platform-ui/pulls/2
1163 lines
28 KiB
Markdown
1163 lines
28 KiB
Markdown
# Yudao UI Admin Vben - 项目结构与开发指南
|
||
|
||
> **专注于 web-antd 项目** - 基于 Vue 3 + Vite + Ant Design Vue 的后台管理系统
|
||
|
||
## 📋 目录
|
||
|
||
- [项目架构](#项目架构)
|
||
- [目录结构详解](#目录结构详解)
|
||
- [通用组件库](#通用组件库)
|
||
- [配置文件说明](#配置文件说明)
|
||
- [主题定制](#主题定制)
|
||
- [登录布局定制](#登录布局定制)
|
||
- [开发调试指南](#开发调试指南)
|
||
- [本次会话修改记录](#本次会话修改记录)
|
||
|
||
---
|
||
|
||
## 🏗️ 项目架构
|
||
|
||
### 整体结构
|
||
|
||
本项目采用 **Monorepo** 架构,使用 **pnpm workspace** 管理多个包:
|
||
|
||
```
|
||
yudao-ui-admin-vben/
|
||
├── apps/ # 应用层
|
||
│ ├── web-antd/ # Ant Design Vue 版本 (主要使用)
|
||
│ ├── web-ele/ # Element Plus 版本
|
||
│ ├── web-naive/ # Naive UI 版本
|
||
│ └── web-tdesign/ # TDesign 版本
|
||
├── packages/ # 公共包
|
||
│ ├── @core/ # 核心包
|
||
│ ├── effects/ # 业务效果包
|
||
│ ├── locales/ # 国际化
|
||
│ ├── stores/ # 状态管理
|
||
│ └── ... # 其他工具包
|
||
├── internal/ # 内部工具
|
||
│ ├── vite-config/ # Vite 配置
|
||
│ ├── tailwind-config/ # Tailwind 配置
|
||
│ └── lint-configs/ # 代码规范配置
|
||
└── docs/ # 文档站点
|
||
```
|
||
|
||
### 技术栈
|
||
|
||
| 技术 | 版本 | 说明 |
|
||
| -------------- | ---- | -------------------------- |
|
||
| Vue | 3.x | 渐进式 JavaScript 框架 |
|
||
| Vite | 5.x | 下一代前端构建工具 |
|
||
| TypeScript | 5.x | 类型安全 |
|
||
| Ant Design Vue | 4.x | UI 组件库 |
|
||
| Pinia | 2.x | 状态管理 |
|
||
| Vue Router | 4.x | 路由管理 |
|
||
| Tailwind CSS | 3.x | 原子化 CSS |
|
||
| VueUse | 10.x | Vue Composition API 工具集 |
|
||
|
||
---
|
||
|
||
## 📁 目录结构详解
|
||
|
||
### apps/web-antd/ - 主应用目录
|
||
|
||
```
|
||
apps/web-antd/
|
||
├── public/ # 静态资源
|
||
│ ├── favicon.ico # 网站图标
|
||
│ ├── login-illustration.svg # 登录页插图
|
||
│ ├── images/ # 图片资源
|
||
│ ├── static/ # 静态文件
|
||
│ └── tinymce/ # 富文本编辑器资源
|
||
│
|
||
├── src/
|
||
│ ├── adapter/ # 适配器层
|
||
│ │ ├── component.ts # 组件适配器 (全局组件注册)
|
||
│ │ ├── form.ts # 表单适配器
|
||
│ │ └── vxe-table.ts # 表格适配器
|
||
│ │
|
||
│ ├── api/ # API 接口层 (201 个文件)
|
||
│ │ ├── core/ # 核心接口 (登录、权限等)
|
||
│ │ ├── system/ # 系统管理
|
||
│ │ ├── infra/ # 基础设施
|
||
│ │ ├── bpm/ # 工作流
|
||
│ │ ├── mall/ # 商城
|
||
│ │ ├── mp/ # 公众号
|
||
│ │ ├── pay/ # 支付
|
||
│ │ ├── ai/ # AI 相关
|
||
│ │ ├── iot/ # 物联网
|
||
│ │ └── erp/ # ERP
|
||
│ │
|
||
│ ├── assets/ # 资源文件
|
||
│ │ ├── images/ # 图片
|
||
│ │ └── svg/ # SVG 图标
|
||
│ │
|
||
│ ├── components/ # 业务组件 (54 个文件)
|
||
│ │ ├── Bpmnjs/ # 工作流设计器
|
||
│ │ ├── Button/ # 按钮组件
|
||
│ │ ├── ContentWrap/ # 内容包裹器
|
||
│ │ ├── Crontab/ # 定时任务配置
|
||
│ │ ├── Dialog/ # 对话框
|
||
│ │ ├── Editor/ # 编辑器
|
||
│ │ ├── Form/ # 表单
|
||
│ │ ├── Icon/ # 图标
|
||
│ │ ├── ImageViewer/ # 图片查看器
|
||
│ │ ├── InputNumber/ # 数字输入框
|
||
│ │ ├── JsonEditor/ # JSON 编辑器
|
||
│ │ ├── Search/ # 搜索
|
||
│ │ ├── SimpleProcessDesignerV2/ # 流程设计器 V2
|
||
│ │ ├── Table/ # 表格
|
||
│ │ ├── UploadFile/ # 文件上传
|
||
│ │ └── UploadImg/ # 图片上传
|
||
│ │
|
||
│ ├── layouts/ # 布局组件
|
||
│ │ ├── auth.vue # 登录页布局 (自定义)
|
||
│ │ ├── auth-original.vue # 原始登录页布局 (备份)
|
||
│ │ ├── basic.vue # 基础布局
|
||
│ │ └── index.ts # 导出
|
||
│ │
|
||
│ ├── locales/ # 本地化
|
||
│ │ ├── langs/ # 语言包
|
||
│ │ │ ├── en-US.json # 英文
|
||
│ │ │ └── zh-CN.json # 中文
|
||
│ │ └── index.ts
|
||
│ │
|
||
│ ├── plugins/ # 插件
|
||
│ │ └── form-create.ts # 表单构建器插件
|
||
│ │
|
||
│ ├── router/ # 路由配置
|
||
│ │ ├── guard.ts # 路由守卫
|
||
│ │ ├── index.ts # 路由实例
|
||
│ │ └── routes/ # 路由定义
|
||
│ │ ├── core.ts # 核心路由 (登录、404等)
|
||
│ │ └── modules/ # 业务路由模块
|
||
│ │
|
||
│ ├── store/ # 状态管理 (Pinia)
|
||
│ │ ├── index.ts
|
||
│ │ ├── modules/
|
||
│ │ │ ├── auth.ts # 认证状态
|
||
│ │ │ ├── dict.ts # 字典状态
|
||
│ │ │ └── tenant.ts # 租户状态
|
||
│ │
|
||
│ ├── utils/ # 工具函数
|
||
│ │ ├── dict.ts # 字典工具
|
||
│ │ ├── tree.ts # 树形数据工具
|
||
│ │ └── ...
|
||
│ │
|
||
│ ├── views/ # 页面视图 (1233 个文件)
|
||
│ │ ├── _core/ # 核心页面
|
||
│ │ │ ├── authentication/ # 认证相关
|
||
│ │ │ │ ├── login.vue # 登录页
|
||
│ │ │ │ ├── code-login.vue # 验证码登录
|
||
│ │ │ │ ├── qrcode-login.vue # 二维码登录
|
||
│ │ │ │ └── forget-password.vue # 忘记密码
|
||
│ │ │ ├── profile/ # 个人中心
|
||
│ │ │ └── ...
|
||
│ │ ├── system/ # 系统管理
|
||
│ │ ├── bpm/ # 工作流
|
||
│ │ ├── mall/ # 商城
|
||
│ │ ├── mp/ # 公众号
|
||
│ │ ├── pay/ # 支付
|
||
│ │ ├── ai/ # AI
|
||
│ │ ├── iot/ # 物联网
|
||
│ │ └── erp/ # ERP
|
||
│ │
|
||
│ ├── app.vue # 根组件
|
||
│ ├── bootstrap.ts # 应用启动配置
|
||
│ ├── main.ts # 应用入口
|
||
│ └── preferences.ts # 偏好设置
|
||
│
|
||
├── index.html # HTML 模板
|
||
├── vite.config.mts # Vite 配置
|
||
├── tsconfig.json # TypeScript 配置
|
||
├── tailwind.config.mjs # Tailwind 配置
|
||
├── package.json # 依赖管理
|
||
└── LOGIN_LAYOUT_README.md # 登录布局文档
|
||
```
|
||
|
||
---
|
||
|
||
## 🧩 通用组件库
|
||
|
||
### packages/@core/ - 核心组件包
|
||
|
||
#### 1. shadcn-ui (`packages/@core/ui-kit/shadcn-ui`)
|
||
|
||
基于 shadcn/ui 的 Vue 组件库,提供高质量的基础 UI 组件:
|
||
|
||
```typescript
|
||
// 导入方式
|
||
import {
|
||
VbenButton,
|
||
VbenInput,
|
||
VbenModal,
|
||
VbenToast,
|
||
VbenDropdown,
|
||
VbenSelect,
|
||
VbenPinInput, // 验证码输入框
|
||
VbenLoading,
|
||
VbenSpinner,
|
||
// ... 更多组件
|
||
} from '@vben-core/shadcn-ui';
|
||
```
|
||
|
||
**常用组件**:
|
||
|
||
- **按钮类**: `VbenButton`, `VbenIconButton`
|
||
- **输入类**: `VbenInput`, `VbenInputPassword`, `VbenPinInput`
|
||
- **选择类**: `VbenSelect`, `VbenDropdown`, `VbenCheckbox`, `VbenRadio`
|
||
- **反馈类**: `VbenModal`, `VbenToast`, `VbenAlert`, `VbenLoading`
|
||
- **布局类**: `VbenCard`, `VbenTabs`, `VbenCollapse`
|
||
|
||
#### 2. form-ui (`packages/@core/ui-kit/form-ui`)
|
||
|
||
强大的表单构建器:
|
||
|
||
```typescript
|
||
import { useVbenForm, VbenFormSchema } from '@vben-core/form-ui';
|
||
|
||
// 表单配置示例
|
||
const formSchema: VbenFormSchema[] = [
|
||
{
|
||
component: 'VbenInput',
|
||
fieldName: 'username',
|
||
label: '用户名',
|
||
rules: z.string().min(1, { message: '请输入用户名' }),
|
||
},
|
||
{
|
||
component: 'VbenInputPassword',
|
||
fieldName: 'password',
|
||
label: '密码',
|
||
rules: z.string().min(6, { message: '密码至少6位' }),
|
||
},
|
||
];
|
||
|
||
const [Form, formApi] = useVbenForm({ schema: formSchema });
|
||
```
|
||
|
||
#### 3. menu-ui (`packages/@core/ui-kit/menu-ui`)
|
||
|
||
菜单组件,支持多级菜单、收缩展开等:
|
||
|
||
```typescript
|
||
import { VbenMenu } from '@vben-core/menu-ui';
|
||
```
|
||
|
||
#### 4. layout-ui (`packages/@core/ui-kit/layout-ui`)
|
||
|
||
布局组件(Header, Sidebar, Content, Footer):
|
||
|
||
```typescript
|
||
import { BasicLayout, LayoutHeader, LayoutSidebar } from '@vben-core/layout-ui';
|
||
```
|
||
|
||
#### 5. popup-ui (`packages/@core/ui-kit/popup-ui`)
|
||
|
||
弹窗、抽屉组件:
|
||
|
||
```typescript
|
||
import { VbenModal, VbenDrawer } from '@vben-core/popup-ui';
|
||
```
|
||
|
||
---
|
||
|
||
### packages/effects/ - 业务效果包
|
||
|
||
#### 1. layouts (`packages/effects/layouts`)
|
||
|
||
布局组件和小部件:
|
||
|
||
```typescript
|
||
import {
|
||
// 布局组件
|
||
AuthPageLayout, // 认证页布局
|
||
LoginIllustration, // 登录插图 (自定义新增)
|
||
|
||
// 小部件
|
||
ThemeToggle, // 主题切换
|
||
LanguageToggle, // 语言切换
|
||
ColorToggle, // 颜色选择器
|
||
LayoutToggle, // 布局切换
|
||
UserDropdown, // 用户下拉菜单
|
||
Breadcrumb, // 面包屑
|
||
GlobalSearch, // 全局搜索
|
||
LockScreen, // 锁屏
|
||
Notification, // 通知
|
||
} from '@vben/layouts';
|
||
```
|
||
|
||
**目录结构**:
|
||
|
||
```
|
||
packages/effects/layouts/src/
|
||
├── authentication/ # 认证相关
|
||
│ ├── authentication.vue # 认证页布局
|
||
│ ├── icons/
|
||
│ │ ├── login-illustration.vue # 登录插图组件
|
||
│ │ └── slogan.vue # Logo/标语组件
|
||
│ └── index.ts # 导出
|
||
├── basic/ # 基础布局
|
||
├── widgets/ # 小部件
|
||
│ ├── theme-toggle.vue
|
||
│ ├── language-toggle.vue
|
||
│ ├── color-toggle.vue # 颜色选择器 (已修改)
|
||
│ └── ...
|
||
└── index.ts
|
||
```
|
||
|
||
#### 2. common-ui (`packages/effects/common-ui`)
|
||
|
||
通用 UI 组件:
|
||
|
||
```typescript
|
||
import {
|
||
// 认证组件
|
||
AuthenticationLogin, // 登录表单
|
||
AuthenticationCodeLogin, // 验证码登录
|
||
AuthenticationForgetPassword, // 忘记密码
|
||
AuthenticationRegister, // 注册
|
||
|
||
// 其他通用组件
|
||
Page, // 页面容器
|
||
DocAlert, // 文档提醒
|
||
Description, // 描述列表
|
||
Ellipsis, // 文本省略
|
||
Iframe, // 内嵌页面
|
||
// ...
|
||
} from '@vben/common-ui';
|
||
```
|
||
|
||
#### 3. hooks (`packages/effects/hooks`)
|
||
|
||
业务相关的 Composition API 钩子:
|
||
|
||
```typescript
|
||
import {
|
||
useWatermark, // 水印
|
||
useTabs, // 标签页管理
|
||
useContentHeight, // 内容高度自适应
|
||
isTenantEnable, // 租户功能是否启用
|
||
} from '@vben/hooks';
|
||
```
|
||
|
||
#### 4. access (`packages/effects/access`)
|
||
|
||
权限控制:
|
||
|
||
```typescript
|
||
import { useAccess } from '@vben/access';
|
||
|
||
// 权限检查
|
||
const { hasAccessByRoles, hasAccessByCodes } = useAccess();
|
||
|
||
// 指令方式
|
||
<button v-access="'system:user:create'">创建用户</button>
|
||
```
|
||
|
||
---
|
||
|
||
### packages/其他包
|
||
|
||
#### locales - 国际化
|
||
|
||
```typescript
|
||
import { $t, setupI18n } from '@vben/locales';
|
||
|
||
// 使用翻译
|
||
$t('authentication.login');
|
||
$t('authentication.username');
|
||
```
|
||
|
||
**语言包位置**:
|
||
|
||
- 中文: `packages/locales/src/langs/zh-CN/*.json`
|
||
- 英文: `packages/locales/src/langs/en-US/*.json`
|
||
|
||
#### stores - 状态管理
|
||
|
||
```typescript
|
||
import {
|
||
useUserStore, // 用户信息
|
||
useAccessStore, // 权限信息
|
||
useTabsStore, // 标签页
|
||
useAppStore, // 应用配置
|
||
} from '@vben/stores';
|
||
|
||
const userStore = useUserStore();
|
||
await userStore.fetchUserInfo();
|
||
```
|
||
|
||
#### preferences - 偏好设置
|
||
|
||
```typescript
|
||
import {
|
||
preferences, // 偏好设置对象
|
||
updatePreferences, // 更新偏好设置
|
||
usePreferences, // 响应式偏好设置
|
||
} from '@vben/preferences';
|
||
|
||
// 读取
|
||
const isDark = preferences.theme.mode === 'dark';
|
||
|
||
// 更新
|
||
updatePreferences({
|
||
theme: {
|
||
colorPrimary: '#FFA00A',
|
||
builtinType: 'amber',
|
||
},
|
||
});
|
||
```
|
||
|
||
#### utils - 工具函数
|
||
|
||
```typescript
|
||
import {
|
||
// 路由工具
|
||
mapTree,
|
||
resetRoutes,
|
||
|
||
// 通用工具
|
||
formatDate,
|
||
formatDateTime,
|
||
openWindow,
|
||
|
||
// 验证器
|
||
isEmail,
|
||
isPhone,
|
||
isUrl,
|
||
} from '@vben/utils';
|
||
```
|
||
|
||
#### constants - 常量定义
|
||
|
||
```typescript
|
||
import {
|
||
// 核心常量
|
||
LOGIN_PATH,
|
||
VBEN_DOC_URL,
|
||
|
||
// 业务枚举
|
||
DictEnum,
|
||
SystemEnum,
|
||
BpmEnum,
|
||
// ...
|
||
} from '@vben/constants';
|
||
```
|
||
|
||
---
|
||
|
||
## ⚙️ 配置文件说明
|
||
|
||
### 1. Vite 配置 (`vite.config.mts`)
|
||
|
||
```typescript
|
||
import { defineConfig } from '@vben/vite-config';
|
||
|
||
export default defineConfig(async () => {
|
||
return {
|
||
application: {},
|
||
vite: {
|
||
server: {
|
||
proxy: {
|
||
'/admin-api': {
|
||
target: 'http://localhost:48080/admin-api',
|
||
changeOrigin: true,
|
||
rewrite: (path) => path.replace(/^\/admin-api/, ''),
|
||
},
|
||
},
|
||
},
|
||
},
|
||
};
|
||
});
|
||
```
|
||
|
||
### 2. TypeScript 配置 (`tsconfig.json`)
|
||
|
||
```json
|
||
{
|
||
"$schema": "https://json.schemastore.org/tsconfig",
|
||
"extends": "@vben/tsconfig/web-app.json",
|
||
"compilerOptions": {
|
||
"baseUrl": ".",
|
||
"paths": {
|
||
"#/*": ["./src/*"]
|
||
},
|
||
"allowJs": true
|
||
},
|
||
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||
}
|
||
```
|
||
|
||
**路径别名**:
|
||
|
||
- `#/*` → `./src/*` (应用内部)
|
||
- `@vben/*` → `packages/*` (公共包)
|
||
|
||
### 3. Tailwind 配置 (`tailwind.config.mjs`)
|
||
|
||
```javascript
|
||
import { defineConfig } from '@vben/tailwind-config';
|
||
|
||
export default defineConfig({
|
||
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||
// 自定义配置...
|
||
});
|
||
```
|
||
|
||
### 4. 环境变量 (`.env.*`)
|
||
|
||
```bash
|
||
# .env.development
|
||
VITE_APP_TITLE=芋道管理系统
|
||
VITE_APP_BASE_API=/admin-api
|
||
VITE_APP_NAMESPACE=vben-web-antd
|
||
```
|
||
|
||
---
|
||
|
||
## 🎨 主题定制
|
||
|
||
### 1. 新增主题色
|
||
|
||
**文件**: `packages/@core/preferences/src/constants.ts`
|
||
|
||
```typescript
|
||
const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
|
||
{
|
||
color: 'hsl(37 100% 52%)', // #FFA00A
|
||
type: 'amber',
|
||
},
|
||
// ... 其他颜色
|
||
];
|
||
|
||
export const COLOR_PRESETS = [...BUILT_IN_THEME_PRESETS].slice(0, 8);
|
||
```
|
||
|
||
**类型定义**: `packages/@core/base/typings/src/app.d.ts`
|
||
|
||
```typescript
|
||
type BuiltinThemeType =
|
||
| 'amber' // 新增
|
||
| 'default'
|
||
| 'orange'
|
||
| 'red'
|
||
// ...
|
||
| (Record<never, never> & string);
|
||
```
|
||
|
||
**默认主题**: `packages/@core/preferences/src/config.ts`
|
||
|
||
```typescript
|
||
const defaultPreferences: Preferences = {
|
||
theme: {
|
||
builtinType: 'amber', // 默认主题类型
|
||
colorPrimary: 'hsl(37 100% 52%)', // 主色调
|
||
mode: 'dark', // 暗色模式
|
||
radius: '0.5', // 圆角
|
||
},
|
||
// ...
|
||
};
|
||
```
|
||
|
||
### 2. Loading 页面定制
|
||
|
||
**文件**: `internal/vite-config/src/plugins/inject-app-loading/default-loading.html`
|
||
|
||
```html
|
||
<style data-app-loading="inject-css">
|
||
/* 主题色 */
|
||
.loader::after {
|
||
background: hsl(var(--primary, 37 100% 52%)); /* 橙色 #FFA00A */
|
||
}
|
||
|
||
/* 标题样式 */
|
||
.title {
|
||
font-weight: 600 !important;
|
||
font-family:
|
||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
**注意**: 修改后需要**重启开发服务器**才能生效!
|
||
|
||
---
|
||
|
||
## 🔐 登录布局定制
|
||
|
||
### 自定义登录页
|
||
|
||
**文件**: `apps/web-antd/src/layouts/auth.vue`
|
||
|
||
**主要特性**:
|
||
|
||
- ✅ 橙色渐变背景 (`rgb(218,125,68)` → `#FFA00A`)
|
||
- ✅ 浮动插图动画(左侧)
|
||
- ✅ 表单卡片居右
|
||
- ✅ 支持 Light/Dark 主题
|
||
- ✅ 响应式布局
|
||
- ✅ 快速过渡动画
|
||
|
||
**组件引用**:
|
||
|
||
```typescript
|
||
import { LanguageToggle, LoginIllustration, ThemeToggle } from '@vben/layouts';
|
||
```
|
||
|
||
**详细文档**: 参见 `apps/web-antd/LOGIN_LAYOUT_README.md`
|
||
|
||
### 登录页面
|
||
|
||
**文件**: `apps/web-antd/src/views/_core/authentication/login.vue`
|
||
|
||
**功能**:
|
||
|
||
- 用户名/密码登录
|
||
- 图形验证码
|
||
- 记住密码
|
||
- 第三方登录(手机、二维码)
|
||
|
||
**表单配置示例**:
|
||
|
||
```typescript
|
||
const formSchema = computed((): VbenFormSchema[] => [
|
||
{
|
||
component: 'VbenInput',
|
||
fieldName: 'username',
|
||
label: $t('authentication.username'),
|
||
rules: z.string().min(1),
|
||
},
|
||
{
|
||
component: 'VbenInputPassword',
|
||
fieldName: 'password',
|
||
label: $t('authentication.password'),
|
||
rules: z.string().min(1),
|
||
},
|
||
// ...
|
||
]);
|
||
```
|
||
|
||
### 验证码登录/忘记密码
|
||
|
||
**文件**:
|
||
|
||
- `apps/web-antd/src/views/_core/authentication/code-login.vue`
|
||
- `apps/web-antd/src/views/_core/authentication/forget-password.vue`
|
||
|
||
**验证码组件** (`VbenPinInput`):
|
||
|
||
- ✅ 验证码长度: 6 位
|
||
- ✅ 发送前验证手机号
|
||
- ✅ 倒计时 60 秒
|
||
- ✅ 失败自动清除倒计时
|
||
|
||
**修复**: `packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue`
|
||
|
||
```typescript
|
||
async function handleSend(e: Event) {
|
||
try {
|
||
e?.preventDefault();
|
||
// ✅ 先验证手机号
|
||
await handleSendCode();
|
||
// ✅ 验证成功后才开始倒计时
|
||
countdown.value = maxTime;
|
||
startCountdown();
|
||
} catch (error) {
|
||
// ✅ 失败清除倒计时
|
||
countdown.value = 0;
|
||
clearTimeout(timer.value);
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠️ 开发调试指南
|
||
|
||
### 启动项目
|
||
|
||
```bash
|
||
# 安装依赖
|
||
pnpm install
|
||
|
||
# 启动开发服务器
|
||
pnpm dev
|
||
|
||
# 或者只启动 web-antd
|
||
pnpm --filter @vben/web-antd dev
|
||
```
|
||
|
||
### 构建项目
|
||
|
||
```bash
|
||
# 构建所有应用
|
||
pnpm build
|
||
|
||
# 只构建 web-antd
|
||
pnpm --filter @vben/web-antd build
|
||
```
|
||
|
||
### 代码规范
|
||
|
||
```bash
|
||
# ESLint 检查
|
||
pnpm lint
|
||
|
||
# 格式化代码
|
||
pnpm format
|
||
|
||
# 类型检查
|
||
pnpm typecheck
|
||
```
|
||
|
||
### 常用命令
|
||
|
||
```bash
|
||
# 清理所有 node_modules
|
||
pnpm clean
|
||
|
||
# 清理并重新安装
|
||
pnpm clean && pnpm install
|
||
|
||
# 查看依赖树
|
||
pnpm list --depth 0
|
||
|
||
# 更新依赖
|
||
pnpm update
|
||
```
|
||
|
||
### 调试技巧
|
||
|
||
#### 1. Vue DevTools
|
||
|
||
安装 Vue DevTools 浏览器扩展,可以查看:
|
||
|
||
- 组件树
|
||
- Pinia 状态
|
||
- 路由信息
|
||
- 性能分析
|
||
|
||
#### 2. 网络请求调试
|
||
|
||
打开浏览器开发者工具 Network 面板:
|
||
|
||
- 查看 API 请求/响应
|
||
- 检查请求头/响应头
|
||
- 查看接口耗时
|
||
|
||
#### 3. 控制台调试
|
||
|
||
```typescript
|
||
// 在组件中使用 console
|
||
console.log('当前路由:', router.currentRoute.value);
|
||
console.log('用户信息:', userStore.userInfo);
|
||
console.log('权限列表:', accessStore.accessCodes);
|
||
```
|
||
|
||
#### 4. 断点调试
|
||
|
||
在 VS Code 中配置 `.vscode/launch.json`:
|
||
|
||
```json
|
||
{
|
||
"version": "0.2.0",
|
||
"configurations": [
|
||
{
|
||
"type": "chrome",
|
||
"request": "launch",
|
||
"name": "Launch Chrome",
|
||
"url": "http://localhost:5173",
|
||
"webRoot": "${workspaceFolder}/apps/web-antd"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
#### 5. 性能分析
|
||
|
||
使用 Vue DevTools Performance 功能:
|
||
|
||
- 记录组件渲染时间
|
||
- 查找性能瓶颈
|
||
- 优化重渲染
|
||
|
||
---
|
||
|
||
## 📝 本次会话修改记录
|
||
|
||
### 1. 主题色定制 (#FFA00A - 橙色)
|
||
|
||
#### 文件: `packages/@core/preferences/src/constants.ts`
|
||
|
||
```typescript
|
||
// 新增 amber 主题色
|
||
const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
|
||
{
|
||
color: 'hsl(37 100% 52%)', // #FFA00A
|
||
type: 'amber',
|
||
},
|
||
// ...
|
||
];
|
||
export const COLOR_PRESETS = [...BUILT_IN_THEME_PRESETS].slice(0, 8); // 7→8
|
||
```
|
||
|
||
#### 文件: `packages/@core/base/typings/src/app.d.ts`
|
||
|
||
```typescript
|
||
type BuiltinThemeType =
|
||
| 'amber' // ← 新增
|
||
| 'default';
|
||
// ...
|
||
```
|
||
|
||
#### 文件: `packages/@core/preferences/src/config.ts`
|
||
|
||
```typescript
|
||
const defaultPreferences: Preferences = {
|
||
theme: {
|
||
builtinType: 'amber', // ← 设为默认
|
||
colorPrimary: 'hsl(37 100% 52%)', // ← 设为默认
|
||
// ...
|
||
},
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 登录布局重构
|
||
|
||
#### 文件: `apps/web-antd/src/layouts/auth.vue`
|
||
|
||
**完全重构,新增功能**:
|
||
|
||
- ✅ 橙色渐变背景 (从 `rgb(218,125,68)` 到 `#FFA00A`)
|
||
- ✅ 浮动插图组件 (左侧,带动画)
|
||
- ✅ 白色 Logo 文字,带阴影
|
||
- ✅ 表单卡片右对齐,垂直居中
|
||
- ✅ 快速过渡动画 (0.2s/0.15s)
|
||
- ✅ 响应式布局
|
||
- ✅ 保留原有 Toolbar (主题、语言切换)
|
||
|
||
**关键代码**:
|
||
|
||
```vue
|
||
<template>
|
||
<div class="relative flex h-screen w-full overflow-hidden font-sans">
|
||
<!-- 橙色渐变背景 -->
|
||
<div
|
||
class="to-[#FFA00A]/8 absolute inset-0 bg-gradient-to-r from-[rgb(218,125,68)] via-[#FFA00A]/30"
|
||
>
|
||
<!-- 浮动插图 -->
|
||
<div
|
||
class="absolute -left-[5%] top-1/2 hidden h-[48rem] w-[65%] -translate-y-1/2 lg:block"
|
||
>
|
||
<LoginIllustration :alt="appName" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Logo - 白色字体 -->
|
||
<div class="absolute left-4 top-4">
|
||
<img :src="logo" :alt="appName" />
|
||
<span
|
||
class="text-xl font-semibold text-white drop-shadow-[0_2px_4px_rgba(0,0,0,0.3)]"
|
||
>
|
||
{{ appName }}
|
||
</span>
|
||
</div>
|
||
|
||
<!-- 登录卡片 - 右侧居中 -->
|
||
<div class="flex w-full flex-1 items-center justify-end">
|
||
<div class="w-full md:w-[480px] lg:mr-[10%]">
|
||
<div class="rounded-[2.5rem] p-8">
|
||
<RouterView />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
/* 快速过渡动画 */
|
||
.fade-enter-active {
|
||
transition:
|
||
opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
|
||
transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
</style>
|
||
```
|
||
|
||
#### 备份文件: `apps/web-antd/src/layouts/auth-original.vue`
|
||
|
||
保留了原始布局,可随时切换回去。
|
||
|
||
---
|
||
|
||
### 3. 登录插图组件
|
||
|
||
#### 文件: `packages/effects/layouts/src/authentication/icons/login-illustration.vue`
|
||
|
||
**新建组件**:
|
||
|
||
```vue
|
||
<script setup lang="ts">
|
||
defineOptions({
|
||
name: 'LoginIllustration',
|
||
});
|
||
|
||
defineProps<{
|
||
alt?: string;
|
||
}>();
|
||
</script>
|
||
|
||
<template>
|
||
<div class="login-illustration-container">
|
||
<img
|
||
src="/login-illustration.svg"
|
||
:alt="alt || 'Login Illustration'"
|
||
class="w-full animate-float opacity-40"
|
||
/>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.login-illustration-container img {
|
||
transform: scale(1.2);
|
||
animation: float-smooth 3s ease-in-out 0ms infinite;
|
||
}
|
||
|
||
@keyframes float-smooth {
|
||
0%,
|
||
100% {
|
||
transform: scale(1.2) translateY(0);
|
||
}
|
||
50% {
|
||
transform: scale(1.2) translateY(-15px);
|
||
}
|
||
}
|
||
</style>
|
||
```
|
||
|
||
#### 文件: `packages/effects/layouts/src/authentication/index.ts`
|
||
|
||
```typescript
|
||
export { default as AuthPageLayout } from './authentication.vue';
|
||
export { default as LoginIllustration } from './icons/login-illustration.vue'; // ← 新增导出
|
||
export * from './types';
|
||
```
|
||
|
||
#### 静态资源: `apps/web-antd/public/login-illustration.svg`
|
||
|
||
插图 SVG 文件放置在 public 目录。
|
||
|
||
---
|
||
|
||
### 4. 登录页优化
|
||
|
||
#### 文件: `apps/web-antd/src/views/_core/authentication/login.vue`
|
||
|
||
**修改内容**:
|
||
|
||
- ✅ 移除内部标题,使用组件默认标题
|
||
- ✅ 新增"其他登录方式"分隔线
|
||
- ✅ 图标按钮样式统一
|
||
- ✅ 手机登录 + 二维码登录(微信已注释)
|
||
- ✅ 多语言支持
|
||
|
||
**其他登录方式**:
|
||
|
||
```vue
|
||
<template>
|
||
<div class="mt-8">
|
||
<!-- 分隔线 -->
|
||
<div class="relative mb-6 flex justify-center text-xs">
|
||
<span class="relative z-10 bg-background px-3">
|
||
{{ $t('authentication.otherLoginMethods') }}
|
||
</span>
|
||
<div class="absolute inset-0 flex items-center">
|
||
<div class="w-full border-t"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 登录按钮 -->
|
||
<div class="flex justify-center gap-8">
|
||
<!-- 手机登录 -->
|
||
<button
|
||
class="flex size-12 items-center justify-center rounded-2xl border bg-slate-50 transition-all hover:scale-110 hover:shadow-md"
|
||
@click="$router.push('/auth/code-login')"
|
||
>
|
||
<svg><!-- 手机图标 --></svg>
|
||
</button>
|
||
|
||
<!-- 二维码登录 -->
|
||
<button
|
||
class="flex size-12 items-center justify-center rounded-2xl border bg-slate-50 transition-all hover:scale-110 hover:shadow-md"
|
||
@click="$router.push('/auth/qrcode-login')"
|
||
>
|
||
<svg><!-- 二维码图标 --></svg>
|
||
</button>
|
||
|
||
<!-- 微信登录 (已注释) -->
|
||
<!-- <button ...>...</button> -->
|
||
</div>
|
||
</div>
|
||
</template>
|
||
```
|
||
|
||
---
|
||
|
||
### 5. 验证码功能修复
|
||
|
||
#### 文件: `packages/@core/ui-kit/shadcn-ui/src/components/pin-input/input.vue`
|
||
|
||
**问题**: 点击"发送验证码"后立即开始倒计时,即使手机号验证失败。
|
||
|
||
**修复**: 先验证手机号,成功后才开始倒计时。
|
||
|
||
```typescript
|
||
async function handleSend(e: Event) {
|
||
try {
|
||
e?.preventDefault();
|
||
// ✅ 先执行验证码发送逻辑(包含手机号验证)
|
||
await handleSendCode();
|
||
// ✅ 只有成功后才开始倒计时
|
||
countdown.value = maxTime;
|
||
startCountdown();
|
||
} catch (error) {
|
||
console.error('Failed to send code:', error);
|
||
// ✅ 如果发送失败,确保倒计时停止
|
||
countdown.value = 0;
|
||
clearTimeout(timer.value);
|
||
emit('sendError', error);
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 文件: `apps/web-antd/src/views/_core/authentication/forget-password.vue`
|
||
|
||
#### 文件: `apps/web-antd/src/views/_core/authentication/code-login.vue`
|
||
|
||
**修改**: 验证码长度从 4 位改为 6 位。
|
||
|
||
```typescript
|
||
const CODE_LENGTH = 6; // 4 → 6
|
||
```
|
||
|
||
---
|
||
|
||
### 6. 国际化新增
|
||
|
||
#### 文件: `packages/locales/src/langs/zh-CN/authentication.json`
|
||
|
||
```json
|
||
{
|
||
"otherLoginMethods": "或使用以下方式登录",
|
||
"contactSupport": "遇到问题?",
|
||
"support": "联系支持"
|
||
}
|
||
```
|
||
|
||
#### 文件: `packages/locales/src/langs/en-US/authentication.json`
|
||
|
||
```json
|
||
{
|
||
"otherLoginMethods": "Or sign in with",
|
||
"contactSupport": "Need help?",
|
||
"support": "Contact Support"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 7. Loading 页面优化
|
||
|
||
#### 文件: `internal/vite-config/src/plugins/inject-app-loading/default-loading.html`
|
||
|
||
**问题**:
|
||
|
||
- Loading 动画颜色先蓝后橙(闪烁)
|
||
- 标题字体粗细变化
|
||
|
||
**修复**:
|
||
|
||
```html
|
||
<style data-app-loading="inject-css">
|
||
/* 修改主题色回退值为橙色 */
|
||
.loader::before {
|
||
background: hsl(var(--primary, 37 100% 52%) / 50%); /* 蓝色 → 橙色 */
|
||
}
|
||
|
||
.loader::after {
|
||
background: hsl(var(--primary, 37 100% 52%)); /* 蓝色 → 橙色 */
|
||
}
|
||
|
||
/* 锁定标题样式 */
|
||
.title {
|
||
font-weight: 600 !important;
|
||
font-family:
|
||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
||
color: rgb(0 0 0 / 85%) !important;
|
||
}
|
||
|
||
.dark .title {
|
||
color: #fff !important;
|
||
}
|
||
</style>
|
||
```
|
||
|
||
**注意**: 修改后需要**重启开发服务器**才能生效!
|
||
|
||
---
|
||
|
||
## 📚 相关文档
|
||
|
||
- [登录布局详细说明](./LOGIN_LAYOUT_README.md)
|
||
- [项目官方文档](https://doc.vben.pro)
|
||
- [Vite 文档](https://vitejs.dev)
|
||
- [Vue 3 文档](https://vuejs.org)
|
||
- [Ant Design Vue 文档](https://antdv.com)
|
||
- [Tailwind CSS 文档](https://tailwindcss.com)
|
||
|
||
---
|
||
|
||
## 🔍 快速查找
|
||
|
||
### 我要修改...
|
||
|
||
| 需求 | 文件位置 |
|
||
| --- | --- |
|
||
| **登录页布局** | `apps/web-antd/src/layouts/auth.vue` |
|
||
| **登录表单** | `apps/web-antd/src/views/_core/authentication/login.vue` |
|
||
| **验证码登录** | `apps/web-antd/src/views/_core/authentication/code-login.vue` |
|
||
| **忘记密码** | `apps/web-antd/src/views/_core/authentication/forget-password.vue` |
|
||
| **主题色** | `packages/@core/preferences/src/constants.ts` |
|
||
| **Loading 页面** | `internal/vite-config/src/plugins/inject-app-loading/default-loading.html` |
|
||
| **国际化** | `packages/locales/src/langs/zh-CN/*.json` |
|
||
| **路由配置** | `apps/web-antd/src/router/routes/` |
|
||
| **API 接口** | `apps/web-antd/src/api/` |
|
||
| **全局组件** | `apps/web-antd/src/components/` |
|
||
| **工具函数** | `apps/web-antd/src/utils/` |
|
||
| **状态管理** | `apps/web-antd/src/store/` |
|
||
|
||
### 常见问题
|
||
|
||
#### Q: 如何切换回原始登录布局?
|
||
|
||
A: 修改路由配置,将 `auth.vue` 改为 `auth-original.vue`。
|
||
|
||
#### Q: 如何添加新的主题色?
|
||
|
||
A: 参见 [主题定制](#主题定制) 章节。
|
||
|
||
#### Q: 修改 Loading 页面后不生效?
|
||
|
||
A: 必须重启开发服务器 (`Ctrl+C` 然后 `pnpm dev`)。
|
||
|
||
#### Q: 如何自定义登录插图?
|
||
|
||
A: 替换 `apps/web-antd/public/login-illustration.svg` 文件。
|
||
|
||
#### Q: 验证码长度如何修改?
|
||
|
||
A: 修改对应页面的 `CODE_LENGTH` 常量。
|
||
|
||
---
|