Vue3转换前置操作
This commit is contained in:
6
TouchVueThree/.env.development
Normal file
6
TouchVueThree/.env.development
Normal file
@@ -0,0 +1,6 @@
|
||||
# 基础环境变量示例
|
||||
VITE_API_BASE_URL=http://www.yishi.com
|
||||
VITE_API_BASE_URL2=https://s2.siyuguanli.com:9991
|
||||
VITE_API_WS_URL=wss://s2.siyuguanli.com:9993
|
||||
# VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
|
||||
VITE_APP_TITLE=存客宝
|
||||
6
TouchVueThree/.env.production
Normal file
6
TouchVueThree/.env.production
Normal file
@@ -0,0 +1,6 @@
|
||||
# 基础环境变量示例
|
||||
VITE_API_BASE_URL=https://ckbapi.quwanzhi.com
|
||||
VITE_API_BASE_URL2=https://s2.siyuguanli.com:9991
|
||||
VITE_API_WS_URL=wss://s2.siyuguanli.com:9993
|
||||
# VITE_API_BASE_URL=http://www.yishi.com
|
||||
VITE_APP_TITLE=存客宝
|
||||
@@ -1,3 +1,5 @@
|
||||
const path = require('path')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
@@ -9,20 +11,63 @@ module.exports = {
|
||||
'eslint:recommended',
|
||||
'plugin:vue/vue3-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
// './.eslintrc-auto-import.json', // 自动导入的全局变量(安装依赖后自动生成)
|
||||
'prettier', // Prettier 兼容
|
||||
'./.eslintrc-auto-import.json', // 自动导入的全局变量(安装依赖后自动生成)
|
||||
],
|
||||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module',
|
||||
project: './tsconfig.json',
|
||||
extraFileExtensions: ['.vue'],
|
||||
},
|
||||
plugins: ['vue', '@typescript-eslint', 'prettier'],
|
||||
settings: {
|
||||
// 支持路径别名解析
|
||||
'import/resolver': {
|
||||
alias: {
|
||||
map: [
|
||||
['@', path.resolve(__dirname, './src')],
|
||||
['@api', path.resolve(__dirname, './src/api')],
|
||||
['@components', path.resolve(__dirname, './src/components')],
|
||||
['@composables', path.resolve(__dirname, './src/composables')],
|
||||
['@stores', path.resolve(__dirname, './src/stores')],
|
||||
['@utils', path.resolve(__dirname, './src/utils')],
|
||||
['@types', path.resolve(__dirname, './src/types')],
|
||||
['@views', path.resolve(__dirname, './src/views')],
|
||||
['@assets', path.resolve(__dirname, './src/assets')],
|
||||
['@layouts', path.resolve(__dirname, './src/layouts')],
|
||||
['@directives', path.resolve(__dirname, './src/directives')],
|
||||
],
|
||||
extensions: ['.ts', '.tsx', '.vue', '.js', '.jsx'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: ['vue', '@typescript-eslint'],
|
||||
rules: {
|
||||
// Vue 规则
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/require-default-prop': 'off',
|
||||
'vue/no-v-html': 'off',
|
||||
|
||||
// TypeScript 规则
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': ['warn', {
|
||||
argsIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
}],
|
||||
'@typescript-eslint/ban-ts-comment': ['error', {
|
||||
'ts-ignore': 'allow-with-description',
|
||||
}],
|
||||
|
||||
// Prettier 规则
|
||||
'prettier/prettier': ['error', {
|
||||
endOfLine: 'auto',
|
||||
}],
|
||||
|
||||
// 通用规则
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-unused-vars': 'off', // 使用 TypeScript 的规则
|
||||
},
|
||||
}
|
||||
|
||||
388
TouchVueThree/PATH_ALIAS_GUIDE.md
Normal file
388
TouchVueThree/PATH_ALIAS_GUIDE.md
Normal file
@@ -0,0 +1,388 @@
|
||||
# 路径别名使用指南
|
||||
|
||||
## 📁 已配置的路径别名
|
||||
|
||||
项目已为所有核心目录配置了路径别名,让您的导入语句更简洁、更清晰。
|
||||
|
||||
### 完整别名列表
|
||||
|
||||
| 别名 | 实际路径 | 用途 |
|
||||
|------|---------|------|
|
||||
| `@` | `./src` | 根目录 |
|
||||
| `@api` | `./src/api` | API 接口 |
|
||||
| `@components` | `./src/components` | 公共组件 |
|
||||
| `@composables` | `./src/composables` | 组合式函数 |
|
||||
| `@stores` | `./src/stores` | Pinia Store |
|
||||
| `@utils` | `./src/utils` | 工具函数 |
|
||||
| `@types` | `./src/types` | TypeScript 类型 |
|
||||
| `@views` | `./src/views` | 页面组件 |
|
||||
| `@assets` | `./src/assets` | 静态资源 |
|
||||
| `@layouts` | `./src/layouts` | 布局组件 |
|
||||
| `@directives` | `./src/directives` | 自定义指令 |
|
||||
|
||||
---
|
||||
|
||||
## ✨ 使用示例
|
||||
|
||||
### ❌ 不推荐:相对路径
|
||||
|
||||
```typescript
|
||||
// 深层嵌套,难以维护
|
||||
import { useUserStore } from '../../../../stores/modules/user'
|
||||
import ChatWindow from '../../../components/business/ChatWindow/index.vue'
|
||||
import { formatDate } from '../../../utils/date'
|
||||
```
|
||||
|
||||
### ✅ 推荐:路径别名
|
||||
|
||||
```typescript
|
||||
// 清晰明了,易于维护
|
||||
import { useUserStore } from '@stores/modules/user'
|
||||
import ChatWindow from '@components/business/ChatWindow/index.vue'
|
||||
import { formatDate } from '@utils/date'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 实际应用场景
|
||||
|
||||
### 1. 在 Vue 组件中使用
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// API 调用
|
||||
import { getUserInfoApi } from '@api/modules/user'
|
||||
|
||||
// Store
|
||||
import { useUserStore } from '@stores/modules/user'
|
||||
import { useWeChatMessagesStore } from '@stores/modules/wechat/messages'
|
||||
|
||||
// Composables
|
||||
import { useAuth } from '@composables/core/useAuth'
|
||||
import { useMessages } from '@composables/business/useMessages'
|
||||
|
||||
// 组件
|
||||
import ChatWindow from '@components/business/ChatWindow/index.vue'
|
||||
import Loading from '@components/common/Loading/index.vue'
|
||||
|
||||
// 工具函数
|
||||
import { formatDate } from '@utils/date'
|
||||
import { isValidPhone } from '@utils/validator'
|
||||
|
||||
// 类型
|
||||
import type { User } from '@types/user'
|
||||
import type { ChatMessage } from '@types/wechat'
|
||||
|
||||
// 资源
|
||||
import logo from '@assets/images/logo.png'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 在 TypeScript 文件中使用
|
||||
|
||||
```typescript
|
||||
// src/composables/business/useChat.ts
|
||||
import { ref } from 'vue'
|
||||
import { useWeChatMessagesStore } from '@stores/modules/wechat/messages'
|
||||
import { sendMessageApi } from '@api/modules/wechat'
|
||||
import { formatTimestamp } from '@utils/date'
|
||||
import type { ChatMessage } from '@types/wechat'
|
||||
|
||||
export function useChat() {
|
||||
const messagesStore = useWeChatMessagesStore()
|
||||
const loading = ref(false)
|
||||
|
||||
const sendMessage = async (content: string) => {
|
||||
loading.value = true
|
||||
try {
|
||||
await sendMessageApi({ content })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { sendMessage, loading }
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 在 Store 中使用
|
||||
|
||||
```typescript
|
||||
// src/stores/modules/user.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { loginApi, getUserInfoApi } from '@api/modules/user'
|
||||
import { setToken, getToken } from '@utils/storage'
|
||||
import type { User, LoginParams } from '@types/user'
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
const user = ref<User | null>(null)
|
||||
const token = ref(getToken())
|
||||
|
||||
const login = async (params: LoginParams) => {
|
||||
const result = await loginApi(params)
|
||||
token.value = result.token
|
||||
user.value = result.user
|
||||
setToken(result.token)
|
||||
}
|
||||
|
||||
return { user, token, login }
|
||||
})
|
||||
```
|
||||
|
||||
### 4. 在路由配置中使用
|
||||
|
||||
```typescript
|
||||
// src/router/routes.ts
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
import DefaultLayout from '@layouts/DefaultLayout.vue'
|
||||
import ChatLayout from '@layouts/ChatLayout.vue'
|
||||
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/login',
|
||||
component: () => import('@views/Login/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/chat',
|
||||
component: ChatLayout,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@views/Chat/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/dashboard',
|
||||
component: DefaultLayout,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@views/Dashboard/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### 5. 在 SCSS 中使用
|
||||
|
||||
```vue
|
||||
<style scoped lang="scss">
|
||||
// SCSS 中使用 @ 别名访问资源
|
||||
.logo {
|
||||
background-image: url('@assets/images/logo.png');
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-image: url('@assets/icons/user.svg');
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 配置说明
|
||||
|
||||
路径别名已在以下三个配置文件中同步配置:
|
||||
|
||||
### 1. `vite.config.ts` - Vite 构建工具
|
||||
|
||||
```typescript
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
'@api': path.resolve(__dirname, './src/api'),
|
||||
'@components': path.resolve(__dirname, './src/components'),
|
||||
'@composables': path.resolve(__dirname, './src/composables'),
|
||||
'@stores': path.resolve(__dirname, './src/stores'),
|
||||
'@utils': path.resolve(__dirname, './src/utils'),
|
||||
'@types': path.resolve(__dirname, './src/types'),
|
||||
'@views': path.resolve(__dirname, './src/views'),
|
||||
'@assets': path.resolve(__dirname, './src/assets'),
|
||||
'@layouts': path.resolve(__dirname, './src/layouts'),
|
||||
'@directives': path.resolve(__dirname, './src/directives'),
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### 2. `tsconfig.json` - TypeScript 配置
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"@api/*": ["./src/api/*"],
|
||||
"@components/*": ["./src/components/*"],
|
||||
"@composables/*": ["./src/composables/*"],
|
||||
"@stores/*": ["./src/stores/*"],
|
||||
"@utils/*": ["./src/utils/*"],
|
||||
"@types/*": ["./src/types/*"],
|
||||
"@views/*": ["./src/views/*"],
|
||||
"@assets/*": ["./src/assets/*"],
|
||||
"@layouts/*": ["./src/layouts/*"],
|
||||
"@directives/*": ["./src/directives/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. `.eslintrc.cjs` - ESLint 配置
|
||||
|
||||
```javascript
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
alias: {
|
||||
map: [
|
||||
['@', path.resolve(__dirname, './src')],
|
||||
['@api', path.resolve(__dirname, './src/api')],
|
||||
// ... 其他别名
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 最佳实践
|
||||
|
||||
### 1. 优先使用更具体的别名
|
||||
|
||||
```typescript
|
||||
// ✅ 推荐:使用具体的别名
|
||||
import { useUserStore } from '@stores/modules/user'
|
||||
import ChatWindow from '@components/business/ChatWindow/index.vue'
|
||||
|
||||
// ⚠️ 可以但不推荐:使用通用别名
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import ChatWindow from '@/components/business/ChatWindow/index.vue'
|
||||
```
|
||||
|
||||
**原因**:
|
||||
- 更具体的别名能让代码意图更清晰
|
||||
- IDE 的自动补全会更准确
|
||||
- 重构时更容易全局搜索和替换
|
||||
|
||||
### 2. 保持导入语句的一致性
|
||||
|
||||
```typescript
|
||||
// ✅ 推荐:按类型分组导入
|
||||
<script setup lang="ts">
|
||||
// 1. Vue 核心(自动导入)
|
||||
// 2. 第三方库
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 3. Stores
|
||||
import { useUserStore } from '@stores/modules/user'
|
||||
|
||||
// 4. Composables
|
||||
import { useAuth } from '@composables/core/useAuth'
|
||||
|
||||
// 5. API
|
||||
import { getUserInfoApi } from '@api/modules/user'
|
||||
|
||||
// 6. 组件
|
||||
import ChatWindow from '@components/business/ChatWindow/index.vue'
|
||||
|
||||
// 7. 工具函数
|
||||
import { formatDate } from '@utils/date'
|
||||
|
||||
// 8. 类型
|
||||
import type { User } from '@types/user'
|
||||
|
||||
// 9. 资源
|
||||
import logo from '@assets/images/logo.png'
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 类型导入使用 type 关键字
|
||||
|
||||
```typescript
|
||||
// ✅ 推荐:显式使用 type
|
||||
import type { User } from '@types/user'
|
||||
import type { ChatMessage } from '@types/wechat'
|
||||
|
||||
// ❌ 不推荐:混合导入
|
||||
import { User, ChatMessage } from '@types/user'
|
||||
```
|
||||
|
||||
### 4. 动态导入也可使用别名
|
||||
|
||||
```typescript
|
||||
// 路由懒加载
|
||||
const routes = [
|
||||
{
|
||||
path: '/chat',
|
||||
component: () => import('@views/Chat/index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/dashboard',
|
||||
component: () => import('@views/Dashboard/index.vue'),
|
||||
},
|
||||
]
|
||||
|
||||
// 动态组件加载
|
||||
const AsyncComponent = defineAsyncComponent(() =>
|
||||
import('@components/business/ChatWindow/index.vue')
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q1: 路径别名不生效,IDE 报错?
|
||||
|
||||
**解决方案**:
|
||||
1. 确保运行了 `pnpm install`
|
||||
2. 重启 VSCode 或 IDE
|
||||
3. 检查 `tsconfig.json` 和 `vite.config.ts` 配置是否正确
|
||||
4. 运行 `pnpm dev` 启动开发服务器
|
||||
|
||||
### Q2: ESLint 提示找不到模块?
|
||||
|
||||
**解决方案**:
|
||||
1. 确保 `.eslintrc-auto-import.json` 文件已生成
|
||||
2. 检查 `.eslintrc.cjs` 中的路径别名配置
|
||||
3. 运行 `pnpm lint` 检查配置
|
||||
|
||||
### Q3: SCSS 中使用别名报错?
|
||||
|
||||
**解决方案**:
|
||||
在 SCSS 中使用别名时,确保使用 `@use` 或正确的 URL 格式:
|
||||
|
||||
```scss
|
||||
// ✅ 正确
|
||||
.logo {
|
||||
background-image: url('@assets/images/logo.png');
|
||||
}
|
||||
|
||||
// 或者使用波浪号
|
||||
.logo {
|
||||
background-image: url('~@assets/images/logo.png');
|
||||
}
|
||||
```
|
||||
|
||||
### Q4: 类型提示不完整?
|
||||
|
||||
**解决方案**:
|
||||
1. 运行 `pnpm type-check` 检查类型
|
||||
2. 确保 `src/auto-imports.d.ts` 和 `src/components.d.ts` 已生成
|
||||
3. 重启 TypeScript 服务(VSCode: `Ctrl+Shift+P` → `TypeScript: Restart TS Server`)
|
||||
|
||||
---
|
||||
|
||||
## 📚 总结
|
||||
|
||||
路径别名的优势:
|
||||
- ✅ 代码更简洁、可读性更强
|
||||
- ✅ 重构时更容易维护
|
||||
- ✅ 避免相对路径错误
|
||||
- ✅ IDE 自动补全更准确
|
||||
- ✅ 团队协作更统一
|
||||
|
||||
现在您可以在项目中愉快地使用路径别名了! 🎉
|
||||
@@ -148,10 +148,10 @@ TouchVueThree/
|
||||
|
||||
- **组件文件**:PascalCase(大驼峰)
|
||||
- `ChatWindow.vue`, `MessageList.vue`
|
||||
|
||||
|
||||
- **工具文件**:camelCase(小驼峰)
|
||||
- `common.ts`, `useAuth.ts`
|
||||
|
||||
|
||||
- **类型文件**:camelCase 或 kebab-case
|
||||
- `user.ts`, `api.d.ts`
|
||||
|
||||
@@ -185,13 +185,13 @@ import { useUserStore } from '@/stores'
|
||||
|
||||
export function useAuth() {
|
||||
const userStore = useUserStore()
|
||||
|
||||
|
||||
const isLoggedIn = computed(() => userStore.isLoggedIn)
|
||||
|
||||
|
||||
const login = async (credentials) => {
|
||||
// 登录逻辑
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
isLoggedIn,
|
||||
login
|
||||
@@ -210,15 +210,15 @@ export const useUserStore = defineStore('user', () => {
|
||||
// State
|
||||
const user = ref(null)
|
||||
const token = ref('')
|
||||
|
||||
|
||||
// Getters
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
|
||||
|
||||
// Actions
|
||||
const setUser = (userData) => {
|
||||
user.value = userData
|
||||
}
|
||||
|
||||
|
||||
return { user, token, isLoggedIn, setUser }
|
||||
}, {
|
||||
persist: {
|
||||
@@ -318,6 +318,6 @@ pnpm analyze
|
||||
|
||||
---
|
||||
|
||||
**更新时间**: 2026-01-12
|
||||
**版本**: 2.0.0
|
||||
**更新时间**: 2026-01-12
|
||||
**版本**: 2.0.0
|
||||
**技术栈**: Vue 3.4 + TypeScript 5.4 + Element Plus 2.5 + Pinia 2.1
|
||||
|
||||
402
TouchVueThree/QUICK_START.md
Normal file
402
TouchVueThree/QUICK_START.md
Normal file
@@ -0,0 +1,402 @@
|
||||
# TouchVueThree 快速开始指南
|
||||
|
||||
## 🚀 项目已完成配置
|
||||
|
||||
### ✅ 已完成的工作
|
||||
|
||||
1. **目录结构创建** ✅
|
||||
- 完整的 PC 端目录结构
|
||||
- 模块化的代码组织
|
||||
|
||||
2. **package.json 优化** ✅
|
||||
- 移除移动端相关依赖
|
||||
- 添加 PC 端必需依赖
|
||||
- 优化打包配置
|
||||
|
||||
3. **Vite 配置优化** ✅
|
||||
- 自动导入配置
|
||||
- 路径别名配置
|
||||
- 打包优化配置
|
||||
- Gzip 压缩
|
||||
|
||||
4. **样式系统** ✅
|
||||
- variables.scss (全局变量)
|
||||
- mixins.scss (混入工具)
|
||||
- reset.scss (样式重置)
|
||||
- global.scss (全局样式)
|
||||
|
||||
---
|
||||
|
||||
## 📦 第一步:安装依赖
|
||||
|
||||
```bash
|
||||
# 进入项目目录
|
||||
cd TouchVueThree
|
||||
|
||||
# 删除旧的 node_modules 和 lock 文件(可选,但推荐)
|
||||
rm -rf node_modules pnpm-lock.yaml
|
||||
|
||||
# 安装所有依赖
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 依赖说明
|
||||
|
||||
**核心框架**:
|
||||
- `vue@^3.4.21` - Vue 3 框架
|
||||
- `vue-router@^4.2.5` - 路由管理
|
||||
- `pinia@^2.1.7` - 状态管理
|
||||
- `pinia-plugin-persistedstate@^3.2.1` - Pinia 持久化
|
||||
|
||||
**UI 组件库**:
|
||||
- `element-plus@^2.5.6` - PC 端 UI 组件
|
||||
- `@element-plus/icons-vue@^2.3.1` - Element Plus 图标
|
||||
|
||||
**数据请求**:
|
||||
- `axios@^1.6.7` - HTTP 客户端
|
||||
- `@tanstack/vue-query@^5.20.0` - 数据请求管理(自动缓存、重试)
|
||||
|
||||
**工具库**:
|
||||
- `@vueuse/core@^10.7.2` - Vue 组合式工具集
|
||||
- `dayjs@^1.11.13` - 日期处理
|
||||
- `lodash-es@^4.17.21` - 工具函数库
|
||||
- `mitt@^3.0.1` - 事件总线
|
||||
- `nanoid@^5.0.4` - ID 生成器
|
||||
|
||||
**图表**:
|
||||
- `echarts@^5.6.0` - 图表库
|
||||
- `vue-echarts@^6.6.8` - Vue ECharts 封装
|
||||
|
||||
**监控**:
|
||||
- `@sentry/vue@^7.100.0` - 错误监控
|
||||
|
||||
---
|
||||
|
||||
## 🔧 第二步:创建环境变量文件
|
||||
|
||||
创建 `.env.development` 文件:
|
||||
|
||||
```env
|
||||
# API 基础地址
|
||||
VITE_API_BASE_URL=http://localhost:3000/api
|
||||
|
||||
# WebSocket 地址
|
||||
VITE_API_WS_URL=ws://localhost:3000/ws
|
||||
|
||||
# 应用标题
|
||||
VITE_APP_TITLE=触客宝 - 开发环境
|
||||
|
||||
# Sentry DSN
|
||||
VITE_SENTRY_DSN=
|
||||
|
||||
# 是否启用 Mock 数据
|
||||
VITE_USE_MOCK=false
|
||||
```
|
||||
|
||||
创建 `.env.production` 文件:
|
||||
|
||||
```env
|
||||
# API 基础地址
|
||||
VITE_API_BASE_URL=https://api.touchkebao.com/api
|
||||
|
||||
# WebSocket 地址
|
||||
VITE_API_WS_URL=wss://api.touchkebao.com/ws
|
||||
|
||||
# 应用标题
|
||||
VITE_APP_TITLE=触客宝
|
||||
|
||||
# Sentry DSN
|
||||
VITE_SENTRY_DSN=your_sentry_dsn_here
|
||||
|
||||
# 是否启用 Mock 数据
|
||||
VITE_USE_MOCK=false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 第三步:启动开发服务器
|
||||
|
||||
```bash
|
||||
# 启动开发服务器
|
||||
pnpm dev
|
||||
|
||||
# 项目将在 http://localhost:8888 启动
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📂 第四步:理解项目结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── api/ # API 接口(按模块划分)
|
||||
├── assets/ # 静态资源和样式
|
||||
├── components/ # 公共组件
|
||||
│ ├── common/ # 通用组件
|
||||
│ └── business/ # 业务组件
|
||||
├── composables/ # 组合式函数
|
||||
│ ├── core/ # 核心功能
|
||||
│ └── business/ # 业务功能
|
||||
├── directives/ # 自定义指令
|
||||
├── layouts/ # 布局组件
|
||||
├── router/ # 路由配置
|
||||
├── stores/ # Pinia 状态管理
|
||||
│ └── modules/ # Store 模块
|
||||
├── types/ # TypeScript 类型
|
||||
├── utils/ # 工具函数
|
||||
└── views/ # 页面组件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔨 开发指南
|
||||
|
||||
### 1. 创建新页面
|
||||
|
||||
```vue
|
||||
<!-- src/views/Example/index.vue -->
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
|
||||
const message = ref('Hello Vue3!')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="example-page">
|
||||
<h1>{{ message }}</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.example-page {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 2. 创建 Store
|
||||
|
||||
```typescript
|
||||
// src/stores/modules/example.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
export const useExampleStore = defineStore('example', () => {
|
||||
// State
|
||||
const count = ref(0)
|
||||
|
||||
// Getters
|
||||
const doubleCount = computed(() => count.value * 2)
|
||||
|
||||
// Actions
|
||||
const increment = () => {
|
||||
count.value++
|
||||
}
|
||||
|
||||
return { count, doubleCount, increment }
|
||||
}, {
|
||||
persist: {
|
||||
key: 'example-store',
|
||||
paths: ['count']
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 3. 创建 API 接口
|
||||
|
||||
```typescript
|
||||
// src/api/modules/example.ts
|
||||
import request from '../request'
|
||||
|
||||
export const getListApi = (params: any) => {
|
||||
return request('/list', params, 'GET')
|
||||
}
|
||||
|
||||
export const createItemApi = (data: any) => {
|
||||
return request('/item', data, 'POST')
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 创建 Composable
|
||||
|
||||
```typescript
|
||||
// src/composables/business/useExample.ts
|
||||
import { ref } from 'vue'
|
||||
import { getListApi } from '@/api/modules/example'
|
||||
|
||||
export function useExample() {
|
||||
const loading = ref(false)
|
||||
const list = ref([])
|
||||
|
||||
const fetchList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
list.value = await getListApi({})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loading,
|
||||
list,
|
||||
fetchList
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 常用命令
|
||||
|
||||
```bash
|
||||
# 开发服务器
|
||||
pnpm dev
|
||||
|
||||
# 类型检查
|
||||
pnpm type-check
|
||||
|
||||
# 代码检查
|
||||
pnpm lint
|
||||
|
||||
# 代码格式化
|
||||
pnpm format
|
||||
|
||||
# 构建生产版本
|
||||
pnpm build
|
||||
|
||||
# 预览生产版本
|
||||
pnpm preview
|
||||
|
||||
# 打包分析
|
||||
pnpm analyze
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 样式使用示例
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="example">
|
||||
<!-- 使用全局工具类 -->
|
||||
<div class="flex-between mb-md">
|
||||
<span class="text-primary font-bold">标题</span>
|
||||
<span class="text-secondary">副标题</span>
|
||||
</div>
|
||||
|
||||
<!-- 使用 SCSS 变量 -->
|
||||
<div class="custom-box">内容</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-box {
|
||||
padding: $spacing-lg;
|
||||
background: $bg-color;
|
||||
border-radius: $border-radius-large;
|
||||
box-shadow: $box-shadow-base;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 调试技巧
|
||||
|
||||
### 1. Vue DevTools
|
||||
|
||||
安装 Vue DevTools 浏览器扩展,用于调试 Vue 组件和 Pinia Store。
|
||||
|
||||
### 2. 自动导入类型提示
|
||||
|
||||
项目已配置自动导入,会自动生成类型文件:
|
||||
- `src/auto-imports.d.ts` - Vue API 类型
|
||||
- `src/components.d.ts` - 组件类型
|
||||
|
||||
如果类型提示不生效,重启 VSCode 或运行:
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
### 3. ESLint 自动修复
|
||||
|
||||
```bash
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **不要手动修改自动生成的文件**:
|
||||
- `src/auto-imports.d.ts`
|
||||
- `src/components.d.ts`
|
||||
- `.eslintrc-auto-import.json`
|
||||
|
||||
2. **使用 SCSS 变量**:
|
||||
全局变量已自动导入,可直接使用 `$primary-color` 等
|
||||
|
||||
3. **路径别名**:
|
||||
项目已配置路径别名,推荐使用:
|
||||
```typescript
|
||||
import { xxx } from '@/xxx' // src/
|
||||
import { xxx } from '@api/xxx' // src/api/
|
||||
import { xxx } from '@components/xxx' // src/components/
|
||||
import { xxx } from '@stores/xxx' // src/stores/
|
||||
```
|
||||
|
||||
4. **TypeScript 严格模式**:
|
||||
项目启用了 TypeScript 严格模式,请注意类型定义
|
||||
|
||||
---
|
||||
|
||||
## 🆘 常见问题
|
||||
|
||||
### Q: pnpm install 失败?
|
||||
|
||||
A: 尝试:
|
||||
```bash
|
||||
# 清理缓存
|
||||
pnpm store prune
|
||||
|
||||
# 重新安装
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### Q: 类型提示不生效?
|
||||
|
||||
A:
|
||||
1. 重启 VSCode
|
||||
2. 运行 `pnpm dev` 生成类型文件
|
||||
3. 检查 `tsconfig.json` 配置
|
||||
|
||||
### Q: 自动导入不生效?
|
||||
|
||||
A:
|
||||
1. 检查 `vite.config.ts` 中的 AutoImport 配置
|
||||
2. 重启开发服务器
|
||||
3. 检查 `.eslintrc-auto-import.json` 是否生成
|
||||
|
||||
---
|
||||
|
||||
## 📚 相关文档
|
||||
|
||||
- [Vue 3 官方文档](https://cn.vuejs.org/)
|
||||
- [Element Plus 官方文档](https://element-plus.org/zh-CN/)
|
||||
- [Pinia 官方文档](https://pinia.vuejs.org/zh/)
|
||||
- [VueUse 官方文档](https://vueuse.org/)
|
||||
- [TanStack Query 官方文档](https://tanstack.com/query/latest)
|
||||
|
||||
---
|
||||
|
||||
## 🎉 开始开发
|
||||
|
||||
现在您可以开始开发了!建议按以下顺序:
|
||||
|
||||
1. ✅ 安装依赖
|
||||
2. ✅ 创建环境变量文件
|
||||
3. ✅ 启动开发服务器
|
||||
4. 🔨 开始编写代码
|
||||
|
||||
祝您开发愉快! 🚀
|
||||
402
TouchVueThree/SETUP_CHECKLIST.md
Normal file
402
TouchVueThree/SETUP_CHECKLIST.md
Normal file
@@ -0,0 +1,402 @@
|
||||
# ✅ TouchVueThree 项目配置完成清单
|
||||
|
||||
> **项目状态**: 🎉 基础架构配置完成,可以开始开发!
|
||||
|
||||
---
|
||||
|
||||
## 📋 已完成的配置
|
||||
|
||||
### 1. ✅ 目录结构 (100%)
|
||||
|
||||
```
|
||||
src/
|
||||
├── api/ ✅ API 接口层
|
||||
│ └── modules/ ✅ 接口模块目录
|
||||
├── assets/ ✅ 静态资源
|
||||
│ └── styles/ ✅ 样式文件
|
||||
│ ├── variables.scss ✅ 全局变量
|
||||
│ ├── mixins.scss ✅ SCSS 混入
|
||||
│ ├── reset.scss ✅ 样式重置
|
||||
│ └── global.scss ✅ 全局样式
|
||||
├── components/ ✅ 公共组件
|
||||
│ ├── common/ ✅ 通用组件
|
||||
│ └── business/ ✅ 业务组件
|
||||
├── composables/ ✅ 组合式函数
|
||||
│ ├── core/ ✅ 核心功能
|
||||
│ └── business/ ✅ 业务功能
|
||||
├── directives/ ✅ 自定义指令
|
||||
├── layouts/ ✅ 布局组件
|
||||
├── router/ ✅ 路由配置
|
||||
├── stores/ ✅ Pinia Store
|
||||
│ └── modules/ ✅ Store 模块
|
||||
│ └── wechat/ ✅ 微信模块
|
||||
├── types/ ✅ TypeScript 类型
|
||||
├── utils/ ✅ 工具函数
|
||||
│ └── sentry/ ✅ 监控工具
|
||||
└── views/ ✅ 页面组件
|
||||
├── Login/ ✅ 登录页
|
||||
├── Chat/ ✅ 聊天页
|
||||
│ └── components/ ✅ 聊天子组件
|
||||
├── Dashboard/ ✅ 数据看板
|
||||
├── Settings/ ✅ 系统设置
|
||||
├── PowerCenter/ ✅ 能力中心
|
||||
│ ├── CustomerManagement/ ✅ 客户管理
|
||||
│ ├── ContentManagement/ ✅ 内容管理
|
||||
│ ├── DataStatistics/ ✅ 数据统计
|
||||
│ └── AiTraining/ ✅ AI 训练
|
||||
└── 404/ ✅ 404 页面
|
||||
```
|
||||
|
||||
### 2. ✅ 依赖配置 (100%)
|
||||
|
||||
#### 核心框架
|
||||
- ✅ `vue@^3.4.21` - Vue 3 框架
|
||||
- ✅ `vue-router@^4.2.5` - 路由管理
|
||||
- ✅ `pinia@^2.1.7` - 状态管理
|
||||
- ✅ `pinia-plugin-persistedstate@^3.2.1` - 状态持久化
|
||||
|
||||
#### UI 组件库
|
||||
- ✅ `element-plus@^2.5.6` - PC 端 UI 组件
|
||||
- ✅ `@element-plus/icons-vue@^2.3.1` - Element Plus 图标
|
||||
|
||||
#### 数据请求
|
||||
- ✅ `axios@^1.6.7` - HTTP 客户端
|
||||
- ✅ `@tanstack/vue-query@^5.20.0` - 数据请求管理
|
||||
|
||||
#### 工具库
|
||||
- ✅ `@vueuse/core@^10.7.2` - Vue 组合式工具集
|
||||
- ✅ `dayjs@^1.11.13` - 日期处理
|
||||
- ✅ `lodash-es@^4.17.21` - 工具函数
|
||||
- ✅ `mitt@^3.0.1` - 事件总线
|
||||
- ✅ `nanoid@^5.0.4` - ID 生成器
|
||||
|
||||
#### 图表
|
||||
- ✅ `echarts@^5.6.0` - 图表库
|
||||
- ✅ `vue-echarts@^6.6.8` - Vue ECharts
|
||||
|
||||
#### 监控
|
||||
- ✅ `@sentry/vue@^7.100.0` - 错误监控
|
||||
|
||||
### 3. ✅ 配置文件 (100%)
|
||||
|
||||
| 文件 | 状态 | 说明 |
|
||||
|------|-----|------|
|
||||
| `package.json` | ✅ | 已优化依赖(移除移动端) |
|
||||
| `vite.config.ts` | ✅ | 完整配置(自动导入、路径别名、打包优化) |
|
||||
| `tsconfig.json` | ✅ | TypeScript 配置 + 完整路径别名 |
|
||||
| `.eslintrc.cjs` | ✅ | ESLint 配置 + 路径别名支持 |
|
||||
| `.prettierrc` | ✅ | 代码格式化配置 |
|
||||
| `.env.development` | ✅ | 开发环境变量 |
|
||||
| `.env.production` | ✅ | 生产环境变量 |
|
||||
|
||||
### 4. ✅ 样式系统 (100%)
|
||||
|
||||
| 文件 | 状态 | 说明 |
|
||||
|------|-----|------|
|
||||
| `variables.scss` | ✅ | 全局变量(颜色、字体、间距等) |
|
||||
| `mixins.scss` | ✅ | SCSS 混入(工具函数) |
|
||||
| `reset.scss` | ✅ | 样式重置 |
|
||||
| `global.scss` | ✅ | 全局样式 + 工具类 |
|
||||
|
||||
### 5. ✅ 路径别名 (100%)
|
||||
|
||||
| 别名 | 路径 | 状态 |
|
||||
|------|-----|-----|
|
||||
| `@` | `./src` | ✅ |
|
||||
| `@api` | `./src/api` | ✅ |
|
||||
| `@components` | `./src/components` | ✅ |
|
||||
| `@composables` | `./src/composables` | ✅ |
|
||||
| `@stores` | `./src/stores` | ✅ |
|
||||
| `@utils` | `./src/utils` | ✅ |
|
||||
| `@types` | `./src/types` | ✅ |
|
||||
| `@views` | `./src/views` | ✅ |
|
||||
| `@assets` | `./src/assets` | ✅ |
|
||||
| `@layouts` | `./src/layouts` | ✅ |
|
||||
| `@directives` | `./src/directives` | ✅ |
|
||||
|
||||
### 6. ✅ 文档 (100%)
|
||||
|
||||
| 文档 | 状态 | 说明 |
|
||||
|------|-----|------|
|
||||
| `PROJECT_STRUCTURE.md` | ✅ | 项目结构说明 |
|
||||
| `QUICK_START.md` | ✅ | 快速开始指南 |
|
||||
| `PATH_ALIAS_GUIDE.md` | ✅ | 路径别名使用指南 |
|
||||
| `SETUP_CHECKLIST.md` | ✅ | 本文档 |
|
||||
|
||||
---
|
||||
|
||||
## 🚀 下一步:开始开发
|
||||
|
||||
### 步骤 1: 安装依赖
|
||||
|
||||
```bash
|
||||
cd TouchVueThree
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 步骤 2: 启动开发服务器
|
||||
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
项目将在 `http://localhost:8888` 启动。
|
||||
|
||||
### 步骤 3: 验证配置
|
||||
|
||||
启动后检查:
|
||||
- ✅ 开发服务器正常启动
|
||||
- ✅ 浏览器自动打开
|
||||
- ✅ 无控制台错误
|
||||
- ✅ 热更新正常工作
|
||||
|
||||
---
|
||||
|
||||
## 📝 开发指南
|
||||
|
||||
### 创建新功能的推荐流程
|
||||
|
||||
#### 1. 定义类型 (`src/types/`)
|
||||
```typescript
|
||||
// src/types/example.ts
|
||||
export interface Example {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 创建 API 接口 (`src/api/modules/`)
|
||||
```typescript
|
||||
// src/api/modules/example.ts
|
||||
import request from '../request'
|
||||
import type { Example } from '@types/example'
|
||||
|
||||
export const getExampleListApi = () => {
|
||||
return request<Example[]>('/example/list', {}, 'GET')
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 创建 Store (`src/stores/modules/`)
|
||||
```typescript
|
||||
// src/stores/modules/example.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { Example } from '@types/example'
|
||||
|
||||
export const useExampleStore = defineStore('example', () => {
|
||||
const list = ref<Example[]>([])
|
||||
|
||||
const fetchList = async () => {
|
||||
list.value = await getExampleListApi()
|
||||
}
|
||||
|
||||
return { list, fetchList }
|
||||
})
|
||||
```
|
||||
|
||||
#### 4. 创建 Composable (`src/composables/business/`)
|
||||
```typescript
|
||||
// src/composables/business/useExample.ts
|
||||
import { useExampleStore } from '@stores/modules/example'
|
||||
|
||||
export function useExample() {
|
||||
const store = useExampleStore()
|
||||
|
||||
return {
|
||||
list: computed(() => store.list),
|
||||
fetchList: store.fetchList
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. 创建页面组件 (`src/views/`)
|
||||
```vue
|
||||
<!-- src/views/Example/index.vue -->
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import { useExample } from '@composables/business/useExample'
|
||||
|
||||
const { list, fetchList } = useExample()
|
||||
|
||||
onMounted(() => {
|
||||
fetchList()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="example-page">
|
||||
<div v-for="item in list" :key="item.id">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.example-page {
|
||||
padding: $spacing-lg;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
#### 6. 添加路由 (`src/router/routes.ts`)
|
||||
```typescript
|
||||
{
|
||||
path: '/example',
|
||||
component: () => import('@views/Example/index.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 可用的 NPM 脚本
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|-----|
|
||||
| `pnpm dev` | 启动开发服务器 |
|
||||
| `pnpm build` | 构建生产版本 |
|
||||
| `pnpm preview` | 预览生产版本 |
|
||||
| `pnpm type-check` | TypeScript 类型检查 |
|
||||
| `pnpm lint` | 代码检查 + 自动修复 |
|
||||
| `pnpm lint:check` | 仅检查,不修复 |
|
||||
| `pnpm format` | 代码格式化 |
|
||||
| `pnpm format:check` | 检查格式是否规范 |
|
||||
| `pnpm analyze` | 打包分析 |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 开发建议
|
||||
|
||||
### 代码规范
|
||||
1. ✅ 使用 TypeScript,避免 `any` 类型
|
||||
2. ✅ 使用 Composition API(`<script setup>`)
|
||||
3. ✅ 使用路径别名(`@/`, `@api/`, `@components/` 等)
|
||||
4. ✅ 组件命名使用 PascalCase
|
||||
5. ✅ 文件命名使用 camelCase 或 kebab-case
|
||||
|
||||
### Git 提交规范
|
||||
```bash
|
||||
# 功能开发
|
||||
git commit -m "feat: 添加用户登录功能"
|
||||
|
||||
# Bug 修复
|
||||
git commit -m "fix: 修复消息列表滚动问题"
|
||||
|
||||
# 样式调整
|
||||
git commit -m "style: 优化聊天界面样式"
|
||||
|
||||
# 重构
|
||||
git commit -m "refactor: 重构消息处理逻辑"
|
||||
|
||||
# 文档
|
||||
git commit -m "docs: 更新 API 文档"
|
||||
|
||||
# 性能优化
|
||||
git commit -m "perf: 优化虚拟滚动性能"
|
||||
```
|
||||
|
||||
### 性能优化建议
|
||||
1. ✅ 使用 `computed` 缓存计算结果
|
||||
2. ✅ 大列表使用虚拟滚动
|
||||
3. ✅ 路由懒加载
|
||||
4. ✅ 图片懒加载
|
||||
5. ✅ 使用 TanStack Query 自动缓存 API 请求
|
||||
|
||||
---
|
||||
|
||||
## 🐛 常见问题排查
|
||||
|
||||
### 问题 1: 依赖安装失败
|
||||
|
||||
```bash
|
||||
# 清理缓存
|
||||
pnpm store prune
|
||||
|
||||
# 删除 node_modules
|
||||
rm -rf node_modules pnpm-lock.yaml
|
||||
|
||||
# 重新安装
|
||||
pnpm install
|
||||
```
|
||||
|
||||
### 问题 2: 端口被占用
|
||||
|
||||
修改 `vite.config.ts`:
|
||||
```typescript
|
||||
server: {
|
||||
port: 8889, // 改为其他端口
|
||||
}
|
||||
```
|
||||
|
||||
### 问题 3: 类型提示不生效
|
||||
|
||||
1. 重启 VSCode
|
||||
2. 运行 `pnpm dev` 生成类型文件
|
||||
3. 检查是否生成了以下文件:
|
||||
- `src/auto-imports.d.ts`
|
||||
- `src/components.d.ts`
|
||||
- `.eslintrc-auto-import.json`
|
||||
|
||||
### 问题 4: ESLint 报错
|
||||
|
||||
```bash
|
||||
# 自动修复
|
||||
pnpm lint
|
||||
|
||||
# 如果还有问题,检查配置
|
||||
cat .eslintrc.cjs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 参考文档
|
||||
|
||||
- [Vue 3 官方文档](https://cn.vuejs.org/)
|
||||
- [Element Plus 官方文档](https://element-plus.org/zh-CN/)
|
||||
- [Pinia 官方文档](https://pinia.vuejs.org/zh/)
|
||||
- [VueUse 官方文档](https://vueuse.org/)
|
||||
- [TanStack Query 官方文档](https://tanstack.com/query/latest)
|
||||
- [Vite 官方文档](https://cn.vitejs.dev/)
|
||||
|
||||
---
|
||||
|
||||
## ✨ 项目特色
|
||||
|
||||
### 1. 自动导入
|
||||
- ✅ Vue API 自动导入(ref、computed、watch 等)
|
||||
- ✅ Vue Router 自动导入
|
||||
- ✅ Pinia 自动导入
|
||||
- ✅ VueUse 自动导入
|
||||
- ✅ TanStack Query 自动导入
|
||||
- ✅ Element Plus 组件自动导入
|
||||
|
||||
### 2. 完整路径别名
|
||||
- ✅ 11 个路径别名覆盖所有目录
|
||||
- ✅ TypeScript、Vite、ESLint 三方同步
|
||||
- ✅ 完美的 IDE 类型提示
|
||||
|
||||
### 3. 专业样式系统
|
||||
- ✅ 完整的 SCSS 变量系统
|
||||
- ✅ 实用的 Mixins 工具集
|
||||
- ✅ 全局工具类(Flex、间距、文本等)
|
||||
- ✅ 与 Element Plus 主题一致
|
||||
|
||||
### 4. 性能优化
|
||||
- ✅ 代码分割
|
||||
- ✅ Gzip 压缩
|
||||
- ✅ 打包分析
|
||||
- ✅ Tree-shaking
|
||||
|
||||
---
|
||||
|
||||
## 🎉 恭喜!
|
||||
|
||||
您的项目已完全配置好,可以开始开发了!
|
||||
|
||||
**推荐的下一步**:
|
||||
1. 运行 `pnpm install` 安装依赖
|
||||
2. 运行 `pnpm dev` 启动开发服务器
|
||||
3. 阅读 `QUICK_START.md` 了解开发流程
|
||||
4. 开始编写您的第一个功能!
|
||||
|
||||
祝您开发愉快!🚀
|
||||
163
TouchVueThree/src/assets/styles/global.scss
Normal file
163
TouchVueThree/src/assets/styles/global.scss
Normal file
@@ -0,0 +1,163 @@
|
||||
// 全局样式
|
||||
|
||||
@use './reset.scss';
|
||||
@use './variables.scss' as *;
|
||||
@use './mixins.scss' as *;
|
||||
|
||||
// ==================== 全局工具类 ====================
|
||||
|
||||
// 文本对齐
|
||||
.text-left { text-align: left; }
|
||||
.text-center { text-align: center; }
|
||||
.text-right { text-align: right; }
|
||||
|
||||
// 文本省略
|
||||
.ellipsis { @include ellipsis; }
|
||||
.ellipsis-2 { @include multi-ellipsis(2); }
|
||||
.ellipsis-3 { @include multi-ellipsis(3); }
|
||||
|
||||
// Flex 布局
|
||||
.flex { display: flex; }
|
||||
.flex-center { @include flex-center; }
|
||||
.flex-between { @include flex-between; }
|
||||
.flex-align-center { @include flex-align-center; }
|
||||
.flex-justify-center { @include flex-justify-center; }
|
||||
.flex-column { flex-direction: column; }
|
||||
.flex-wrap { flex-wrap: wrap; }
|
||||
.flex-1 { flex: 1; }
|
||||
|
||||
// 间距
|
||||
.mt-xs { margin-top: $spacing-xs; }
|
||||
.mt-sm { margin-top: $spacing-sm; }
|
||||
.mt-md { margin-top: $spacing-md; }
|
||||
.mt-lg { margin-top: $spacing-lg; }
|
||||
.mt-xl { margin-top: $spacing-xl; }
|
||||
|
||||
.mb-xs { margin-bottom: $spacing-xs; }
|
||||
.mb-sm { margin-bottom: $spacing-sm; }
|
||||
.mb-md { margin-bottom: $spacing-md; }
|
||||
.mb-lg { margin-bottom: $spacing-lg; }
|
||||
.mb-xl { margin-bottom: $spacing-xl; }
|
||||
|
||||
.ml-xs { margin-left: $spacing-xs; }
|
||||
.ml-sm { margin-left: $spacing-sm; }
|
||||
.ml-md { margin-left: $spacing-md; }
|
||||
.ml-lg { margin-left: $spacing-lg; }
|
||||
.ml-xl { margin-left: $spacing-xl; }
|
||||
|
||||
.mr-xs { margin-right: $spacing-xs; }
|
||||
.mr-sm { margin-right: $spacing-sm; }
|
||||
.mr-md { margin-right: $spacing-md; }
|
||||
.mr-lg { margin-right: $spacing-lg; }
|
||||
.mr-xl { margin-right: $spacing-xl; }
|
||||
|
||||
.p-xs { padding: $spacing-xs; }
|
||||
.p-sm { padding: $spacing-sm; }
|
||||
.p-md { padding: $spacing-md; }
|
||||
.p-lg { padding: $spacing-lg; }
|
||||
.p-xl { padding: $spacing-xl; }
|
||||
|
||||
// 字体大小
|
||||
.text-xs { font-size: $font-size-xs; }
|
||||
.text-sm { font-size: $font-size-sm; }
|
||||
.text-base { font-size: $font-size-base; }
|
||||
.text-lg { font-size: $font-size-lg; }
|
||||
.text-xl { font-size: $font-size-xl; }
|
||||
|
||||
// 字体粗细
|
||||
.font-light { font-weight: $font-weight-light; }
|
||||
.font-normal { font-weight: $font-weight-normal; }
|
||||
.font-medium { font-weight: $font-weight-medium; }
|
||||
.font-bold { font-weight: $font-weight-bold; }
|
||||
|
||||
// 颜色
|
||||
.text-primary { color: $text-color-primary; }
|
||||
.text-regular { color: $text-color-regular; }
|
||||
.text-secondary { color: $text-color-secondary; }
|
||||
.text-placeholder { color: $text-color-placeholder; }
|
||||
|
||||
// 圆角
|
||||
.rounded { border-radius: $border-radius-base; }
|
||||
.rounded-sm { border-radius: $border-radius-small; }
|
||||
.rounded-lg { border-radius: $border-radius-large; }
|
||||
.rounded-full { border-radius: $border-radius-circle; }
|
||||
|
||||
// ==================== 自定义滚动条 ====================
|
||||
|
||||
.custom-scrollbar {
|
||||
@include scrollbar(8px, rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
|
||||
// ==================== 卡片 ====================
|
||||
|
||||
.card {
|
||||
@include card;
|
||||
}
|
||||
|
||||
// ==================== 页面容器 ====================
|
||||
|
||||
.page-container {
|
||||
height: 100%;
|
||||
background-color: $bg-color-page;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
height: 100%;
|
||||
padding: $spacing-lg;
|
||||
overflow-y: auto;
|
||||
@include scrollbar;
|
||||
}
|
||||
|
||||
// ==================== 加载状态 ====================
|
||||
|
||||
.loading-container {
|
||||
@include flex-center;
|
||||
height: 100%;
|
||||
color: $text-color-secondary;
|
||||
}
|
||||
|
||||
// ==================== 空状态 ====================
|
||||
|
||||
.empty-container {
|
||||
@include flex-center;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
color: $text-color-secondary;
|
||||
|
||||
.empty-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: $spacing-md;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 动画 ====================
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.3s;
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.slide-fade-enter-active {
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
.slide-fade-leave-active {
|
||||
transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1);
|
||||
}
|
||||
|
||||
.slide-fade-enter-from,
|
||||
.slide-fade-leave-to {
|
||||
transform: translateX(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
177
TouchVueThree/src/assets/styles/mixins.scss
Normal file
177
TouchVueThree/src/assets/styles/mixins.scss
Normal file
@@ -0,0 +1,177 @@
|
||||
// SCSS 混入(Mixins)
|
||||
|
||||
// ==================== 文本省略 ====================
|
||||
|
||||
// 单行省略
|
||||
@mixin ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 多行省略
|
||||
@mixin multi-ellipsis($lines: 2) {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: $lines;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
// ==================== Flex 布局 ====================
|
||||
|
||||
// Flex 居中
|
||||
@mixin flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// Flex 垂直居中
|
||||
@mixin flex-align-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Flex 水平居中
|
||||
@mixin flex-justify-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// Flex 两端对齐
|
||||
@mixin flex-between {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
// ==================== 清除浮动 ====================
|
||||
|
||||
@mixin clearfix {
|
||||
&::after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 滚动条样式 ====================
|
||||
|
||||
@mixin scrollbar($width: 6px, $thumb-color: rgba(0, 0, 0, 0.2)) {
|
||||
&::-webkit-scrollbar {
|
||||
width: $width;
|
||||
height: $width;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: $thumb-color;
|
||||
border-radius: $width / 2;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 响应式 ====================
|
||||
|
||||
// 媒体查询
|
||||
@mixin respond-to($breakpoint) {
|
||||
@if $breakpoint == xs {
|
||||
@media (max-width: 768px) { @content; }
|
||||
}
|
||||
@else if $breakpoint == sm {
|
||||
@media (min-width: 768px) and (max-width: 992px) { @content; }
|
||||
}
|
||||
@else if $breakpoint == md {
|
||||
@media (min-width: 992px) and (max-width: 1200px) { @content; }
|
||||
}
|
||||
@else if $breakpoint == lg {
|
||||
@media (min-width: 1200px) and (max-width: 1920px) { @content; }
|
||||
}
|
||||
@else if $breakpoint == xl {
|
||||
@media (min-width: 1920px) { @content; }
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 动画 ====================
|
||||
|
||||
// 淡入淡出
|
||||
@mixin fade-in($duration: 0.3s) {
|
||||
animation: fadeIn $duration ease-in;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 滑入
|
||||
@mixin slide-in($direction: 'bottom', $duration: 0.3s) {
|
||||
@if $direction == 'bottom' {
|
||||
animation: slideInBottom $duration ease-out;
|
||||
} @else if $direction == 'top' {
|
||||
animation: slideInTop $duration ease-out;
|
||||
} @else if $direction == 'left' {
|
||||
animation: slideInLeft $duration ease-out;
|
||||
} @else if $direction == 'right' {
|
||||
animation: slideInRight $duration ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInBottom {
|
||||
from {
|
||||
transform: translateY(20px);
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 卡片样式 ====================
|
||||
|
||||
@mixin card($padding: 16px) {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: $padding;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
// ==================== 绝对定位居中 ====================
|
||||
|
||||
@mixin absolute-center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
// ==================== 圆形头像 ====================
|
||||
|
||||
@mixin avatar($size: 40px) {
|
||||
width: $size;
|
||||
height: $size;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
// ==================== 状态点 ====================
|
||||
|
||||
@mixin status-dot($size: 8px, $color: #67c23a) {
|
||||
width: $size;
|
||||
height: $size;
|
||||
border-radius: 50%;
|
||||
background-color: $color;
|
||||
border: 2px solid #fff;
|
||||
}
|
||||
83
TouchVueThree/src/assets/styles/reset.scss
Normal file
83
TouchVueThree/src/assets/styles/reset.scss
Normal file
@@ -0,0 +1,83 @@
|
||||
// CSS 重置样式
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',
|
||||
'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
color: #303133;
|
||||
background-color: #f2f3f5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #409eff;
|
||||
text-decoration: none;
|
||||
transition: color 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #66b1ff;
|
||||
}
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
button {
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
// 滚动条美化
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
// 选中文本颜色
|
||||
::selection {
|
||||
background-color: #409eff;
|
||||
color: #fff;
|
||||
}
|
||||
123
TouchVueThree/src/assets/styles/variables.scss
Normal file
123
TouchVueThree/src/assets/styles/variables.scss
Normal file
@@ -0,0 +1,123 @@
|
||||
// 全局 SCSS 变量
|
||||
|
||||
// ==================== 颜色系统 ====================
|
||||
|
||||
// 主题色(与 Element Plus 保持一致)
|
||||
$primary-color: #409eff;
|
||||
$success-color: #67c23a;
|
||||
$warning-color: #e6a23c;
|
||||
$danger-color: #f56c6c;
|
||||
$info-color: #909399;
|
||||
|
||||
// 文字颜色
|
||||
$text-color-primary: #303133;
|
||||
$text-color-regular: #606266;
|
||||
$text-color-secondary: #909399;
|
||||
$text-color-placeholder: #c0c4cc;
|
||||
|
||||
// 背景颜色
|
||||
$bg-color: #ffffff;
|
||||
$bg-color-page: #f2f3f5;
|
||||
$bg-color-overlay: #ffffff;
|
||||
|
||||
// 边框颜色
|
||||
$border-color: #dcdfe6;
|
||||
$border-color-light: #e4e7ed;
|
||||
$border-color-lighter: #ebeef5;
|
||||
$border-color-extra-light: #f2f6fc;
|
||||
|
||||
// ==================== 尺寸系统 ====================
|
||||
|
||||
// 间距
|
||||
$spacing-xs: 4px;
|
||||
$spacing-sm: 8px;
|
||||
$spacing-md: 12px;
|
||||
$spacing-lg: 16px;
|
||||
$spacing-xl: 20px;
|
||||
$spacing-xxl: 24px;
|
||||
|
||||
// 圆角
|
||||
$border-radius-base: 4px;
|
||||
$border-radius-small: 2px;
|
||||
$border-radius-large: 8px;
|
||||
$border-radius-round: 20px;
|
||||
$border-radius-circle: 50%;
|
||||
|
||||
// 字体大小
|
||||
$font-size-xs: 12px;
|
||||
$font-size-sm: 13px;
|
||||
$font-size-base: 14px;
|
||||
$font-size-md: 15px;
|
||||
$font-size-lg: 16px;
|
||||
$font-size-xl: 18px;
|
||||
$font-size-xxl: 20px;
|
||||
|
||||
// 字体粗细
|
||||
$font-weight-light: 300;
|
||||
$font-weight-normal: 400;
|
||||
$font-weight-medium: 500;
|
||||
$font-weight-bold: 700;
|
||||
|
||||
// 行高
|
||||
$line-height-base: 1.5;
|
||||
$line-height-sm: 1.2;
|
||||
$line-height-lg: 2;
|
||||
|
||||
// ==================== 阴影 ====================
|
||||
|
||||
$box-shadow-base: 0 2px 4px rgba(0, 0, 0, 0.12), 0 0 6px rgba(0, 0, 0, 0.04);
|
||||
$box-shadow-dark: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
$box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
|
||||
// ==================== 过渡动画 ====================
|
||||
|
||||
$transition-base: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
$transition-fade: opacity 0.3s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
$transition-border: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
$transition-color: color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
// ==================== Z-Index ====================
|
||||
|
||||
$z-index-normal: 1;
|
||||
$z-index-top: 1000;
|
||||
$z-index-popper: 2000;
|
||||
$z-index-dialog: 3000;
|
||||
$z-index-message: 4000;
|
||||
|
||||
// ==================== 布局 ====================
|
||||
|
||||
// 头部高度
|
||||
$header-height: 60px;
|
||||
|
||||
// 侧边栏宽度
|
||||
$sidebar-width: 240px;
|
||||
$sidebar-collapsed-width: 64px;
|
||||
|
||||
// 聊天布局
|
||||
$chat-sidebar-width: 280px;
|
||||
$chat-panel-width: 320px;
|
||||
|
||||
// 容器最大宽度
|
||||
$container-max-width: 1400px;
|
||||
|
||||
// ==================== 微信客服专用 ====================
|
||||
|
||||
// 消息气泡
|
||||
$message-bubble-bg-self: #95ec69;
|
||||
$message-bubble-bg-other: #ffffff;
|
||||
$message-bubble-border-color: #e4e7ed;
|
||||
$message-bubble-radius: 8px;
|
||||
|
||||
// 会话列表
|
||||
$session-item-height: 72px;
|
||||
$session-item-hover-bg: #f5f7fa;
|
||||
$session-item-active-bg: #ecf5ff;
|
||||
|
||||
// 联系人列表
|
||||
$contact-item-height: 60px;
|
||||
$contact-avatar-size: 40px;
|
||||
|
||||
// 在线状态
|
||||
$status-online: #67c23a;
|
||||
$status-offline: #909399;
|
||||
$status-busy: #e6a23c;
|
||||
@@ -23,7 +23,17 @@
|
||||
/* Path Alias */
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
"@/*": ["./src/*"],
|
||||
"@api/*": ["./src/api/*"],
|
||||
"@components/*": ["./src/components/*"],
|
||||
"@composables/*": ["./src/composables/*"],
|
||||
"@stores/*": ["./src/stores/*"],
|
||||
"@utils/*": ["./src/utils/*"],
|
||||
"@types/*": ["./src/types/*"],
|
||||
"@views/*": ["./src/views/*"],
|
||||
"@assets/*": ["./src/assets/*"],
|
||||
"@layouts/*": ["./src/layouts/*"],
|
||||
"@directives/*": ["./src/directives/*"]
|
||||
},
|
||||
|
||||
/* Types */
|
||||
|
||||
@@ -19,7 +19,7 @@ export default defineConfig(({ mode }) => {
|
||||
return {
|
||||
plugins: [
|
||||
vue(),
|
||||
|
||||
|
||||
// 自动导入 Vue 3 API、Vue Router、Pinia、VueUse、TanStack Query
|
||||
AutoImport({
|
||||
imports: [
|
||||
@@ -39,7 +39,7 @@ export default defineConfig(({ mode }) => {
|
||||
globalsPropValue: true,
|
||||
},
|
||||
}),
|
||||
|
||||
|
||||
// 自动导入 Element Plus 组件
|
||||
Components({
|
||||
resolvers: [
|
||||
@@ -49,14 +49,14 @@ export default defineConfig(({ mode }) => {
|
||||
],
|
||||
dts: 'src/components.d.ts',
|
||||
}),
|
||||
|
||||
|
||||
// Gzip 压缩
|
||||
compression({
|
||||
algorithm: 'gzip',
|
||||
ext: '.gz',
|
||||
threshold: 10240, // 大于 10KB 的文件才压缩
|
||||
}),
|
||||
|
||||
|
||||
// 打包分析(只在 analyze 模式下启用)
|
||||
mode === 'analyze' && visualizer({
|
||||
open: true,
|
||||
@@ -65,7 +65,7 @@ export default defineConfig(({ mode }) => {
|
||||
filename: 'dist/stats.html'
|
||||
}),
|
||||
].filter(Boolean),
|
||||
|
||||
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
@@ -79,7 +79,7 @@ export default defineConfig(({ mode }) => {
|
||||
'@assets': path.resolve(__dirname, './src/assets'),
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
@@ -88,7 +88,7 @@ export default defineConfig(({ mode }) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
server: {
|
||||
open: true,
|
||||
port: 8888,
|
||||
@@ -101,42 +101,42 @@ export default defineConfig(({ mode }) => {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'assets',
|
||||
sourcemap: false,
|
||||
chunkSizeWarningLimit: 2000,
|
||||
|
||||
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
// 核心框架
|
||||
'vue-vendor': ['vue', 'vue-router', 'pinia'],
|
||||
|
||||
|
||||
// UI 组件库
|
||||
'element-plus': ['element-plus', '@element-plus/icons-vue'],
|
||||
|
||||
|
||||
// 工具库
|
||||
'utils': ['axios', 'dayjs', '@vueuse/core', 'lodash-es', 'mitt', 'nanoid'],
|
||||
|
||||
|
||||
// 数据管理
|
||||
'query': ['@tanstack/vue-query'],
|
||||
|
||||
|
||||
// 图表库
|
||||
'echarts': ['echarts', 'vue-echarts'],
|
||||
},
|
||||
|
||||
|
||||
chunkFileNames: 'assets/js/[name]-[hash].js',
|
||||
entryFileNames: 'assets/js/[name]-[hash].js',
|
||||
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
minify: 'esbuild',
|
||||
target: 'es2015',
|
||||
},
|
||||
|
||||
|
||||
// 依赖预构建优化
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
|
||||
Reference in New Issue
Block a user