mgs-配置前端开发环境
This commit is contained in:
1 parent
b5377a184a
commit
fb0121cced
35 files changed
+2555
-35
No files matched your search
+26
@@ -0,0 +1,26 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# 前端
|
||||
frontend/node_modules
|
||||
frontend/*.local
|
||||
frontend/production
|
||||
frontend/dist
|
||||
frontend/test
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,11 @@
|
||||
# 开发环境
|
||||
NODE_ENV = "development"
|
||||
|
||||
# 开发环境接口地址
|
||||
VITE_API_BASE_URL = '/devApi'
|
||||
|
||||
# # 开发环境打包名称
|
||||
# VITE_OUTDIR='dev'
|
||||
|
||||
# 开发环境地址前缀
|
||||
VITE_ADDRESS_BASE_URL = './'
|
||||
@@ -0,0 +1,11 @@
|
||||
# 正式环境
|
||||
NODE_ENV = "production"
|
||||
|
||||
# 正式环境接口地址
|
||||
VITE_API_BASE_URL = '/proApi'
|
||||
|
||||
# 正式环境打包名称
|
||||
VITE_OUTDIR='production'
|
||||
|
||||
# 正式环境地址前缀
|
||||
VITE_ADDRESS_BASE_URL = '/production/'
|
||||
@@ -0,0 +1,11 @@
|
||||
# 测试环境
|
||||
NODE_ENV = "test"
|
||||
|
||||
# 测试环境接口地址
|
||||
VITE_API_BASE_URL = '/testApi'
|
||||
|
||||
# 测试环境打包名称
|
||||
VITE_OUTDIR='test'
|
||||
|
||||
# 测试环境地址前缀
|
||||
VITE_ADDRESS_BASE_URL = '/test/'
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<!--
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-07-29 09:37:26
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-07-29 16:55:21
|
||||
* @FilePath: /vue-demo3.0/README.md
|
||||
* @Description: This is the default setting. Please set `customMade`. Open koroFileHeader for configuration: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
|
||||
# Vue 3 + TypeScript + Vite Project Template
|
||||
|
||||
This project is based on Vue 3, TypeScript, and Vite, integrating mainstream front-end development tools and best practices. It is suitable for quickly building modern web applications.
|
||||
|
||||
## Recommended Development Environment
|
||||
|
||||
- **IDE**: VS Code
|
||||
- **Plugins**: Volar (recommended to disable Vetur), TypeScript Vue Plugin (Volar)
|
||||
- **Node Version**: Recommended 16+ (tested on 19.0.0)
|
||||
|
||||
## Project Features
|
||||
|
||||
- **Tech Stack**: Vue 3 + TypeScript + Vite
|
||||
- **Routing**: Integrated vue-router, supports dynamic routing
|
||||
- **State Management**: Integrated vuex
|
||||
- **UI Framework**: Supports Element Plus
|
||||
- **Internationalization**: Integrated vue-i18n, supports multi-language switching
|
||||
- **Responsive Adaptation**: postcss-pxtorem automatically converts px to rem
|
||||
- **Code Quality**: Integrated ESLint, Prettier
|
||||
- **Build Optimization**: gzip compression, bundle analysis, code splitting
|
||||
- **Clear Directory Structure**: src contains assets, components, views, router, store, utils, etc.
|
||||
- **Environment Variable Management**: Supports multi-environment configuration, flexible switching, and packaging for different environments
|
||||
- **Static Asset Management**: Automatically categorizes and bundles assets, adds timestamps to prevent caching
|
||||
- **Unit Test Support**: Can be extended with Jest/Vitest
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
├── public/ # Static assets
|
||||
├── src/
|
||||
│ ├── assets/ # Images, styles, and other resources
|
||||
│ ├── components/ # Common components
|
||||
│ ├── views/ # Page views
|
||||
│ ├── router/ # Routing configuration
|
||||
│ ├── store/ # State management
|
||||
│ ├── utils/ # Utility functions
|
||||
│ ├── i18n/ # Internationalization configuration
|
||||
│ ├── App.vue # Root component
|
||||
│ └── main.ts # Entry file
|
||||
├── .env* # Environment variable files
|
||||
├── vite.config.ts # Vite configuration
|
||||
├── tsconfig.json # TypeScript configuration
|
||||
├── README.md # Project documentation
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Install dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Start the development server
|
||||
|
||||
```bash
|
||||
npm run serve
|
||||
```
|
||||
|
||||
3. Build for production
|
||||
|
||||
```bash
|
||||
npm run prod
|
||||
```
|
||||
|
||||
4. Build for test environment
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
5. Preview production build
|
||||
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## Internationalization
|
||||
|
||||
- Chinese and English are supported by default, and you can switch languages at the top right of the login page.
|
||||
- The i18n configuration files are located in the `src/i18n/` directory.
|
||||
|
||||
## Other Notes
|
||||
|
||||
- You can extend more pages and features as needed.
|
||||
- It is recommended to use VS Code for development to enjoy better type hints and code completion.
|
||||
- To customize the theme or adapt to more devices, modify `src/assets/styles/variables.scss`.
|
||||
|
||||
## Contribution & Feedback
|
||||
|
||||
Feel free to submit Issues or PRs to improve features and documentation.
|
||||
|
||||
---
|
||||
|
||||
> This template is integrated with [Vue 3 + TypeScript + Vite] and mainstream plugins, suitable for enterprise-level projects or personal learning use.
|
||||
@@ -0,0 +1,104 @@
|
||||
<!--
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-07-29 09:37:26
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-07-29 16:52:58
|
||||
* @FilePath: /vue-demo3.0/README.md
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
|
||||
# Vue 3 + TypeScript + Vite 项目模板
|
||||
|
||||
本项目基于 Vue 3、TypeScript 和 Vite,集成了主流前端开发工具和最佳实践,适合快速搭建现代 Web 应用。
|
||||
|
||||
## 推荐开发环境
|
||||
|
||||
- **IDE**:VS Code
|
||||
- **插件**:Volar(建议禁用 Vetur)、TypeScript Vue Plugin (Volar)
|
||||
- **Node 版本**:建议 16+ (n本人19.0.0)
|
||||
|
||||
## 项目特性
|
||||
|
||||
- **技术栈**:Vue 3 + TypeScript + Vite
|
||||
- **路由管理**:集成 vue-router,支持动态路由
|
||||
- **状态管理**:集成 vuex
|
||||
- **UI 框架**:支持 Element Plus
|
||||
- **国际化**:集成 vue-i18n,支持多语言切换
|
||||
- **响应式适配**:postcss-pxtorem 自动 px 转 rem
|
||||
- **代码规范**:集成 ESLint、Prettier
|
||||
- **打包优化**:gzip 压缩、打包分析、按需分包
|
||||
- **目录结构清晰**:src 下分 assets、components、views、router、store、utils 等
|
||||
- **环境变量管理**:支持多环境配置,灵活切换,并打包成不同的环境
|
||||
- **静态资源管理**:自动分类打包,带时间戳防缓存
|
||||
- **单元测试支持**:可扩展 Jest/Vitest
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
├── public/ # 静态资源
|
||||
├── src/
|
||||
│ ├── assets/ # 图片、样式等资源
|
||||
│ ├── components/ # 公共组件
|
||||
│ ├── views/ # 页面视图
|
||||
│ ├── router/ # 路由配置
|
||||
│ ├── store/ # 状态管理
|
||||
│ ├── utils/ # 工具函数
|
||||
│ ├── i18n/ # 国际化配置
|
||||
│ ├── App.vue # 根组件
|
||||
│ └── main.ts # 入口文件
|
||||
├── .env* # 环境变量文件
|
||||
├── vite.config.ts # Vite 配置
|
||||
├── tsconfig.json # TypeScript 配置
|
||||
├── README.md # 项目说明
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
1. 安装依赖
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. 启动开发服务器
|
||||
|
||||
```bash
|
||||
npm run serve
|
||||
```
|
||||
|
||||
3. 生产环境打包构建
|
||||
|
||||
```bash
|
||||
npm run prod
|
||||
```
|
||||
4. 测试环境打包构建
|
||||
|
||||
```bash
|
||||
npm run test
|
||||
```
|
||||
|
||||
5. 预览生产环境
|
||||
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## 多语言国际化
|
||||
|
||||
- 默认支持中文和英文,可在登录页右上角切换语言。
|
||||
- 国际化配置文件位于 `src/i18n/` 目录。
|
||||
|
||||
|
||||
## 其他说明
|
||||
|
||||
- 可根据实际需求扩展更多页面和功能。
|
||||
- 推荐使用 VS Code 进行开发,享受更好的类型提示和代码补全。
|
||||
- 如需自定义主题或适配更多设备,可修改 `src/assets/styles/variables.scss`。
|
||||
|
||||
## 贡献与反馈
|
||||
|
||||
欢迎提交 Issue 或 PR,完善功能和文档。
|
||||
|
||||
---
|
||||
|
||||
> 本模板由 [Vue 3 + TypeScript + Vite] 结合主流插件集成,适合企业级项目或个人学习使用
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue3.0 + TS项目模板</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
Generated
+1496
File diff suppressed because it is too large.
Load diff
+24
-11
@@ -1,20 +1,33 @@
|
||||
{
|
||||
"name": "license-manager-frontend",
|
||||
"version": "1.0.0",
|
||||
"name": "vue3_vite",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite",
|
||||
"test": "vue-tsc && vite build --mode test",
|
||||
"prod": "vue-tsc && vite build --mode production",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.0",
|
||||
"vue-router": "^4.2.0",
|
||||
"pinia": "^2.1.0",
|
||||
"axios": "^1.6.0"
|
||||
"axios": "^1.3.6",
|
||||
"element-plus": "^2.3.4",
|
||||
"rollup-plugin-visualizer": "^6.0.3",
|
||||
"sass": "^1.89.2",
|
||||
"vite-plugin-eslint": "^1.8.1",
|
||||
"vue": "^3.2.47",
|
||||
"vue-i18n": "^9.14.5",
|
||||
"vue-router": "^4.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
"vite": "^5.0.0"
|
||||
"@types/node": "^18.16.16",
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"amfe-flexible": "^2.2.1",
|
||||
"postcss-pxtorem": "^6.0.0",
|
||||
"terser": "^5.43.1",
|
||||
"typescript": "^5.8.3",
|
||||
"vite": "^4.3.0",
|
||||
"vite-plugin-compression": "^0.5.1",
|
||||
"vue-tsc": "^3.0.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<!-- 路由出口 -->
|
||||
<router-view></router-view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log(import.meta.env.VITE_API_BASE_URL)
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,44 @@
|
||||
export const errorCodeType = function(status:Number):string{
|
||||
let errMessage:string = "未知错误"
|
||||
switch (status) {
|
||||
case 400:
|
||||
errMessage = '请求失败!请您稍后重试'
|
||||
break
|
||||
case 401:
|
||||
errMessage = '未授权,请重新登录'
|
||||
break
|
||||
case 403:
|
||||
errMessage = '当前账号无权限访问!'
|
||||
break
|
||||
case 404:
|
||||
errMessage = '你所访问的资源不存在!'
|
||||
break
|
||||
case 405:
|
||||
errMessage = '请求方式错误!请您稍后重试'
|
||||
break
|
||||
case 408:
|
||||
errMessage = '请求超时!请您稍后重试'
|
||||
break
|
||||
case 500:
|
||||
errMessage = '服务器端出错'
|
||||
break
|
||||
case 501:
|
||||
errMessage = '网络未实现'
|
||||
break
|
||||
case 502:
|
||||
errMessage = '网络错误'
|
||||
break
|
||||
case 503:
|
||||
errMessage = '服务不可用'
|
||||
break
|
||||
case 504:
|
||||
errMessage = '网络超时'
|
||||
break
|
||||
case 505:
|
||||
errMessage = 'http版本不支持该请求'
|
||||
break
|
||||
default:
|
||||
errMessage = `其他连接错误 --${status}`
|
||||
}
|
||||
return errMessage
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// http状态码
|
||||
import { errorCodeType } from './errorCodeType'
|
||||
//element-plus提示消息组件
|
||||
import { ElMessage } from "element-plus"
|
||||
const envUrl = import.meta.env.VITE_API_BASE_URL
|
||||
|
||||
//使用create方法创建axios实例
|
||||
const Axios = axios.create({
|
||||
timeout: 10000, // 请求超时时间
|
||||
baseURL: envUrl,
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=UTF-8',
|
||||
},
|
||||
// 跨域时候允许携带凭证
|
||||
withCredentials: true
|
||||
})
|
||||
// 添加请求拦截器
|
||||
Axios.interceptors.request.use(config => {
|
||||
const token = localStorage.getItem('blockchain_special_token')
|
||||
// 自定义请求头携带token
|
||||
if(token){ config.headers['token'] = token}
|
||||
return config
|
||||
})
|
||||
// 添加响应拦截器
|
||||
Axios.interceptors.response.use(response => {
|
||||
// console.log(response)
|
||||
const apiData = response.data as any
|
||||
// 这个 Code 是和后端约定的业务 Code
|
||||
const code = apiData.code
|
||||
// 如果没有 Code, 代表这不是项目后端开发的 API
|
||||
if (code === undefined) {
|
||||
ElMessage.error("非本系统的接口")
|
||||
return Promise.reject(new Error("非本系统的接口"))
|
||||
} else {
|
||||
switch (code) {
|
||||
case 0:
|
||||
// code === 0 代表没有错误
|
||||
return apiData
|
||||
default:
|
||||
// 不是正确的 Code
|
||||
ElMessage.error(apiData.message || "Error")
|
||||
return Promise.reject(new Error("Error"))
|
||||
}
|
||||
}
|
||||
}, error => {
|
||||
console.log('Response的error', error)
|
||||
showErrMessage(errorCodeType(error.response.status))
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
/**
|
||||
* @description 显示错误消息
|
||||
* opt 传入参数
|
||||
* err 错误信息
|
||||
* type 消息类型
|
||||
* duration 消息持续时间
|
||||
*/
|
||||
function showErrMessage (errMessage: string, type:any= 'error', duration:number = 5000){
|
||||
ElMessage({
|
||||
message: errMessage,
|
||||
type:type,
|
||||
duration: duration
|
||||
})
|
||||
}
|
||||
|
||||
export default Axios;
|
||||
@@ -0,0 +1,5 @@
|
||||
import Axios from './https'
|
||||
|
||||
export function Login(data:{[key: string]: any}) {
|
||||
return Axios.post('/mock/api/Login',data)
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
@@ -0,0 +1,6 @@
|
||||
$primary-color: #42b983;
|
||||
|
||||
body {
|
||||
font-family: Arial;
|
||||
color: $primary-color;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<!--
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-07-29 09:37:26
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-07-29 11:19:01
|
||||
* @FilePath: /vue-demo3.0/src/components/layout/footer.vue
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
-->
|
||||
<!--
|
||||
* @author: 马国胜
|
||||
* @since: 2023-04-23
|
||||
* footer.vue
|
||||
-->
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import { onBeforeMount, onMounted } from "vue";
|
||||
onBeforeMount(() => {
|
||||
//console.log('2.组件挂载页面之前执行----onBeforeMount')
|
||||
});
|
||||
onMounted(() => {
|
||||
//console.log('3.-组件挂载到页面之后执行-------onMounted')
|
||||
});
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
.text {
|
||||
color: $primary-color;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!--
|
||||
* @author: 马国胜
|
||||
* @since: 2023-04-23
|
||||
* header.vue
|
||||
-->
|
||||
<template>
|
||||
<div></div>
|
||||
</template>
|
||||
|
||||
<script setup lang='ts'>
|
||||
import { onBeforeMount, onMounted } from "vue";
|
||||
onBeforeMount(() => {
|
||||
//console.log('2.组件挂载页面之前执行----onBeforeMount')
|
||||
});
|
||||
onMounted(() => {
|
||||
//console.log('3.-组件挂载到页面之后执行-------onMounted')
|
||||
});
|
||||
</script>
|
||||
<style scoped lang='scss'>
|
||||
.text {
|
||||
color: $primary-color;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-07-29 14:57:17
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-07-29 15:51:27
|
||||
* @FilePath: /vue-demo3.0/src/i18n/index.ts
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
*/
|
||||
import { createI18n, type Composer } from 'vue-i18n'
|
||||
import { nextTick } from 'vue'
|
||||
|
||||
type SupportedLocale = 'zh-CN' | 'en-US' | 'ja-JP'
|
||||
|
||||
const DEFAULT_LOCALE: SupportedLocale = 'zh-CN'
|
||||
const SUPPORTED_LOCALES: SupportedLocale[] = ['zh-CN', 'en-US', 'ja-JP']
|
||||
|
||||
const getStartingLocale = (): SupportedLocale => {
|
||||
const storedLocale = localStorage.getItem('locale') as SupportedLocale | null
|
||||
if (storedLocale && SUPPORTED_LOCALES.includes(storedLocale)) {
|
||||
return storedLocale
|
||||
}
|
||||
|
||||
const browserLocale = navigator.language as SupportedLocale
|
||||
if (SUPPORTED_LOCALES.includes(browserLocale)) {
|
||||
return browserLocale
|
||||
}
|
||||
|
||||
const simplifiedLocale = browserLocale.split('-')[0]
|
||||
const matchedLocale = SUPPORTED_LOCALES.find(locale =>
|
||||
locale.startsWith(simplifiedLocale)
|
||||
)
|
||||
|
||||
return matchedLocale || DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: getStartingLocale(),
|
||||
fallbackLocale: DEFAULT_LOCALE,
|
||||
globalInjection: true,
|
||||
silentTranslationWarn: true,
|
||||
messages: {},
|
||||
datetimeFormats: {},
|
||||
numberFormats: {}
|
||||
})
|
||||
|
||||
// 按需语言包
|
||||
export async function loadLocaleMessages(locale: SupportedLocale): Promise<Record<string, string>> {
|
||||
try {
|
||||
// 修改这里的路径为平级引用
|
||||
const messages = await import(`./locales/${locale}.json`)
|
||||
;(i18n.global as Composer).setLocaleMessage(locale, messages.default)
|
||||
return messages.default
|
||||
} catch (error) {
|
||||
console.error(`Failed to load locale messages for ${locale}`, error)
|
||||
if (locale !== DEFAULT_LOCALE) {
|
||||
return loadLocaleMessages(DEFAULT_LOCALE)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 设置语言
|
||||
export async function setI18nLanguage(locale: SupportedLocale): Promise<void> {
|
||||
if (!SUPPORTED_LOCALES.includes(locale)) {
|
||||
locale = DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
if (!i18n.global.availableLocales.includes(locale)) {
|
||||
await loadLocaleMessages(locale)
|
||||
}
|
||||
|
||||
i18n.global.locale.value = locale
|
||||
document.querySelector('html')?.setAttribute('lang', locale)
|
||||
localStorage.setItem('locale', locale)
|
||||
|
||||
return nextTick()
|
||||
}
|
||||
|
||||
// 初始化
|
||||
setI18nLanguage(i18n.global.locale.value as SupportedLocale)
|
||||
|
||||
export default i18n
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
declare module './locales/*.json' {
|
||||
const value: Record<string, string>
|
||||
export default value
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"login": {
|
||||
"title": "User Login",
|
||||
"username": "Username",
|
||||
"usernamePlaceholder": "Enter username",
|
||||
"password": "Password",
|
||||
"passwordPlaceholder": "Enter password",
|
||||
"remember": "Remember me",
|
||||
"submit": "Login",
|
||||
"success": "Login successful!",
|
||||
"error": {
|
||||
"required": "Please enter username and password",
|
||||
"invalid": "Invalid username or password"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"login": {
|
||||
"title": "ユーザーログイン",
|
||||
"username": "ユーザー名",
|
||||
"usernamePlaceholder": "ユーザー名を入力してください",
|
||||
"password": "パスワード",
|
||||
"passwordPlaceholder": "パスワードを入力してください",
|
||||
"remember": "パスワードを記憶する",
|
||||
"submit": "ログイン",
|
||||
"success": "ログインに成功しました!",
|
||||
"error": {
|
||||
"required": "ユーザー名とパスワードを入力してください",
|
||||
"invalid": "ユーザー名またはパスワードが間違っています"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"login": {
|
||||
"title": "用户登录",
|
||||
"username": "用户名",
|
||||
"usernamePlaceholder": "请输入用户名",
|
||||
"password": "密码",
|
||||
"passwordPlaceholder": "请输入密码",
|
||||
"remember": "记住密码",
|
||||
"submit": "登录",
|
||||
"success": "登录成功!",
|
||||
"error": {
|
||||
"required": "请输入用户名和密码",
|
||||
"invalid": "用户名或密码错误"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import router from './router'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
app.mount('#app')
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* @Author: 13895237362 2205451508@qq.com
|
||||
* @Date: 2025-07-29 09:37:26
|
||||
* @LastEditors: 13895237362 2205451508@qq.com
|
||||
* @LastEditTime: 2025-07-29 15:16:39
|
||||
* @FilePath: /vue-demo3.0/src/main.ts
|
||||
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||
*/
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
import ElementPlus from 'element-plus' //ui框架
|
||||
import 'element-plus/dist/index.css'
|
||||
|
||||
import 'amfe-flexible' // 自适应分辨率与屏幕
|
||||
|
||||
import i18n from './i18n' // 国际化
|
||||
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(router)
|
||||
app.use(ElementPlus)
|
||||
app.use(i18n)
|
||||
app.mount('#app')
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
|
||||
|
||||
// 路由类型:RouteRecordRaw
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "/",
|
||||
component: () => import("@/view/Home.vue"),
|
||||
meta: { title: '首页' }
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
component: () => import("@/view/login.vue"),
|
||||
meta: { title: '登录' }
|
||||
},
|
||||
{
|
||||
path: "/register",
|
||||
component: () => import("@/view/register.vue"),
|
||||
meta: { title: '注册' }
|
||||
},
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
// 路由模式
|
||||
history: createWebHistory(),
|
||||
routes,
|
||||
});
|
||||
|
||||
router.beforeEach(async(to) => {
|
||||
document.title = typeof(to.meta.title) === "string" ? to.meta.title : ""
|
||||
})
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<!-- 切换路由 -->
|
||||
<router-link to="/login">登录</router-link>
|
||||
<router-link to="/register">注册</router-link>
|
||||
<!-- 测试路径别名配置 -->
|
||||
<img src="@assets/image/1.jpg" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
console.log('测试生产环境移出console')
|
||||
console.log(import.meta.env)
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<h2>{{ t('login.title') }}</h2>
|
||||
<form @submit.prevent="handleLogin">
|
||||
<div class="form-group">
|
||||
<label for="username">{{ t('login.username') }}</label>
|
||||
<input
|
||||
id="username"
|
||||
v-model="username"
|
||||
type="text"
|
||||
:placeholder="t('login.usernamePlaceholder')"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">{{ t('login.password') }}</label>
|
||||
<input
|
||||
id="password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
:placeholder="t('login.passwordPlaceholder')"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group remember-row">
|
||||
<input
|
||||
id="remember"
|
||||
v-model="rememberMe"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label for="remember">{{ t('login.remember') }}</label>
|
||||
</div>
|
||||
<button type="submit">{{ t('login.submit') }}</button>
|
||||
</form>
|
||||
<p
|
||||
v-if="errorMsg"
|
||||
class="error"
|
||||
>{{ errorMsg }}</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
||||
// 登录表单数据
|
||||
const username = ref("");
|
||||
const password = ref("");
|
||||
const rememberMe = ref(false);
|
||||
const errorMsg = ref("");
|
||||
|
||||
onMounted(() => {
|
||||
// 记住密码功能
|
||||
const saved = localStorage.getItem("loginInfo");
|
||||
if (saved) {
|
||||
const info = JSON.parse(saved);
|
||||
username.value = info.username || "";
|
||||
password.value = info.password || "";
|
||||
rememberMe.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
function handleLogin() {
|
||||
// 基本验证
|
||||
if (!username.value || !password.value) {
|
||||
errorMsg.value = t("login.error.required");
|
||||
return;
|
||||
}
|
||||
|
||||
// 模拟登录逻辑
|
||||
if (username.value === "admin" && password.value === "123456") {
|
||||
errorMsg.value = "";
|
||||
if (rememberMe.value) {
|
||||
localStorage.setItem(
|
||||
"loginInfo",
|
||||
JSON.stringify({
|
||||
username: username.value,
|
||||
password: password.value,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
localStorage.removeItem("loginInfo");
|
||||
}
|
||||
// 这里可以添加登录成功后的跳转逻辑
|
||||
router.push("/");
|
||||
} else {
|
||||
errorMsg.value = t("login.error.invalid");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.login-container {
|
||||
max-width: 350px;
|
||||
margin: 60px auto;
|
||||
padding: 32px 24px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 24px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
width: 100%;
|
||||
margin-bottom: 18px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.remember-row {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.remember-row input[type="checkbox"] {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
label {
|
||||
margin-bottom: 6px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 8px 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
button[type="submit"] {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #42b983;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
button[type="submit"]:hover {
|
||||
background: #369870;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: #e74c3c;
|
||||
margin-top: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>我是注册组件</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
|
||||
<style scoped></style>
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
/// <reference types="vite/client" />
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
// 解决项目中拿不到 import.meta.env.VITE_API_BASE_URL的值,
|
||||
// 你也可以在项目中使用ts断言 来获取值 如: import.meta.env.VITE_API_BASE_UR as string
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
// "moduleResolution": "bundler",
|
||||
"moduleResolution": "node",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
// 路由别名
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
// 使得 Vite 的类型定义可用
|
||||
"types": ["vite/client"],
|
||||
// 使得导入 JSON 文件时,不需要使用 default 导入
|
||||
"esModuleInterop": true,
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"references": [{ "path": "./tsconfig.node.json" }]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
server: {
|
||||
port: 3000,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8080',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,131 @@
|
||||
import { ConfigEnv, UserConfig, defineConfig, loadEnv } from 'vite'
|
||||
import viteCompression from 'vite-plugin-compression'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
import postCssPxToRem from "postcss-pxtorem" // px转rem插件
|
||||
import { visualizer } from 'rollup-plugin-visualizer' // 打包分析插件
|
||||
// import eslintPlugin from 'vite-plugin-eslint' // 如需ESLint支持可解注
|
||||
|
||||
// 获取当前时间戳,用于构建输出的文件名
|
||||
const Timestamp = new Date().getTime();
|
||||
|
||||
|
||||
// 路径解析辅助函数
|
||||
function _resolve(dir: string) {
|
||||
return path.resolve(__dirname, dir);
|
||||
}
|
||||
|
||||
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||
// 判断当前是否为生产环境
|
||||
const isProd = mode === 'production'
|
||||
// 加载环境变量文件(.env)
|
||||
const env = loadEnv(mode, process.cwd())
|
||||
|
||||
return {
|
||||
// 基础公共路径,从环境变量VITE_ADDRESS_BASE_URL获取
|
||||
base: env.VITE_ADDRESS_BASE_URL,
|
||||
|
||||
// 插件配置
|
||||
plugins: [
|
||||
// Vue插件
|
||||
vue(),
|
||||
// 如需ESLint支持可启用以下插件
|
||||
// eslintPlugin(),
|
||||
|
||||
// Gzip压缩插件(仅生产环境启用)
|
||||
viteCompression({
|
||||
verbose: true, // 显示压缩日志
|
||||
disable: !isProd, // 非生产环境禁用
|
||||
deleteOriginFile: false, // 不删除源文件
|
||||
threshold: 10240, // 文件大于10KB才压缩
|
||||
algorithm: 'gzip', // 压缩算法
|
||||
ext: '.gz', // 压缩文件扩展名
|
||||
}),
|
||||
|
||||
// 打包分析插件(仅生产环境启用)
|
||||
isProd && visualizer({ open: true })
|
||||
].filter(Boolean), // 过滤掉false的插件
|
||||
|
||||
// 开发服务器配置
|
||||
server: {
|
||||
host: '0.0.0.0', // 监听所有IP
|
||||
port: 8080, // 端口号
|
||||
open: true, // 自动打开浏览器
|
||||
https: false, // 不启用HTTPS
|
||||
cors: true, // 启用CORS
|
||||
proxy: { // 代理配置
|
||||
"/test": {
|
||||
target: "http://47.92.24.89:16008", // 目标服务器
|
||||
changeOrigin: true, // 修改请求头中的origin为目标URL
|
||||
rewrite: path => path.replace(/^\/test/, "") // 路径重写
|
||||
},
|
||||
// 可以继续添加其他代理规则
|
||||
}
|
||||
},
|
||||
|
||||
// 模块解析配置
|
||||
resolve: {
|
||||
alias: { // 路径别名
|
||||
'@': _resolve('src'), // 源码目录
|
||||
'@assets': _resolve('src/assets'), // 资源目录
|
||||
'@views': _resolve('src/views'), // 视图目录
|
||||
'@components': _resolve('src/components'), // 组件目录
|
||||
'@utils': _resolve('src/utils'), // 工具函数
|
||||
'@router': _resolve('src/router'), // 路由配置
|
||||
'@store': _resolve('src/store'), // 状态管理
|
||||
}
|
||||
},
|
||||
|
||||
// ESBuild配置
|
||||
esbuild: {
|
||||
pure: isProd ? ["console.log", "debugger"] : [] // 生产环境移除console.log和debugger
|
||||
},
|
||||
|
||||
// 构建配置
|
||||
build: {
|
||||
minify: 'terser', // 使用terser进行代码压缩
|
||||
assetsInlineLimit: 8 * 1024, // 小于8KB的资源转为base64
|
||||
sourcemap: isProd, // 生产环境生成sourcemap
|
||||
outDir: env.VITE_OUTDIR, // 输出目录(从环境变量获取)
|
||||
emptyOutDir: true, // 构建前清空输出目录
|
||||
chunkSizeWarningLimit: 1500, // 块大小警告阈值(KB)
|
||||
rollupOptions: { // Rollup打包配置
|
||||
output: {
|
||||
manualChunks(id) { // 手动分块策略
|
||||
if (id.includes('node_modules')) {
|
||||
// 将node_modules中的依赖单独分块
|
||||
return id.toString().split('node_modules/')[1].split('/')[0].toString();
|
||||
}
|
||||
},
|
||||
// 输出文件命名规则(添加时间戳避免缓存)
|
||||
chunkFileNames: `static/js/[name]-[hash]${Timestamp}.js`,
|
||||
entryFileNames: `static/js/[name]-[hash]${Timestamp}.js`,
|
||||
assetFileNames: `static/[ext]/[name]-[hash]${Timestamp}.[ext]`,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// CSS相关配置
|
||||
css: {
|
||||
preprocessorOptions: { // 预处理器配置
|
||||
scss: {
|
||||
// 全局注入scss变量文件
|
||||
additionalData: `@import "@assets/styles/variables.scss";`
|
||||
}
|
||||
},
|
||||
postcss: { // PostCSS插件
|
||||
plugins: [
|
||||
postCssPxToRem({ // px转rem插件配置
|
||||
rootValue: 192, // 设计稿宽度/10(假设设计稿1920px)
|
||||
propList: ["*", "!border"], // 转换所有属性,除了border
|
||||
})
|
||||
]
|
||||
},
|
||||
},
|
||||
|
||||
// JSON文件处理配置
|
||||
json: {
|
||||
stringify: false
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user