create-vite-vue 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +211 -0
- package/package.json +27 -0
- package/template/axios-js/src/api/index.js +0 -0
- package/template/axios-js/src/utils/request.js +18 -0
- package/template/axios-ts/src/api/index.ts +0 -0
- package/template/axios-ts/src/utils/request.ts +18 -0
- package/template/base-js/README.md +32 -0
- package/template/base-js/index.html +13 -0
- package/template/base-js/jsconfig.json +15 -0
- package/template/base-js/package.json.tpl +23 -0
- package/template/base-js/public/vite.svg +1 -0
- package/template/base-js/src/App.vue +64 -0
- package/template/base-js/src/assets/vue.svg +1 -0
- package/template/base-js/src/main.js.tpl +16 -0
- package/template/base-js/src/style.css +39 -0
- package/template/base-js/vite.config.js +25 -0
- package/template/base-ts/README.md +32 -0
- package/template/base-ts/index.html +13 -0
- package/template/base-ts/package.json.tpl +27 -0
- package/template/base-ts/public/vite.svg +1 -0
- package/template/base-ts/src/App.vue +64 -0
- package/template/base-ts/src/assets/vue.svg +1 -0
- package/template/base-ts/src/main.ts.tpl +16 -0
- package/template/base-ts/src/style.css +39 -0
- package/template/base-ts/src/vite-env.d.ts +6 -0
- package/template/base-ts/tsconfig.app.json +16 -0
- package/template/base-ts/tsconfig.json +22 -0
- package/template/base-ts/tsconfig.node.json +26 -0
- package/template/base-ts/vite.config.ts +25 -0
- package/template/pinia-js/src/stores/index.js +0 -0
- package/template/pinia-ts/src/stores/index.ts +0 -0
- package/template/router-js/src/router/index.js +13 -0
- package/template/router-js/src/views/Home.vue +64 -0
- package/template/router-ts/src/router/index.ts +13 -0
- package/template/router-ts/src/views/Home.vue +64 -0
package/bin/index.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync } from 'child_process'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
import path from 'path'
|
|
5
|
+
import prompts from 'prompts'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
9
|
+
const __dirname = path.dirname(__filename)
|
|
10
|
+
|
|
11
|
+
async function createProject () {
|
|
12
|
+
// 1️⃣ 输入项目名
|
|
13
|
+
let projectName
|
|
14
|
+
while (true) {
|
|
15
|
+
const res = await prompts({
|
|
16
|
+
type: 'text',
|
|
17
|
+
name: 'projectName',
|
|
18
|
+
message: '📦 项目名称',
|
|
19
|
+
validate: v => v ? true : '项目名不能为空'
|
|
20
|
+
})
|
|
21
|
+
projectName = res.projectName
|
|
22
|
+
if (!projectName) process.exit(1)
|
|
23
|
+
|
|
24
|
+
const targetDir = path.resolve(process.cwd(), projectName)
|
|
25
|
+
if (fs.existsSync(targetDir)) {
|
|
26
|
+
console.log('❌ 目录已存在,请重新输入')
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const targetDir = path.resolve(process.cwd(), projectName)
|
|
33
|
+
|
|
34
|
+
const { language } = await prompts({
|
|
35
|
+
type: 'select',
|
|
36
|
+
name: 'language',
|
|
37
|
+
message: '请选择项目语言',
|
|
38
|
+
choices: [
|
|
39
|
+
{ title: 'JavaScript', value: 'js' },
|
|
40
|
+
{ title: 'TypeScript', value: 'ts' }
|
|
41
|
+
]
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
// 2️⃣ 功能选择
|
|
46
|
+
const features = await prompts([
|
|
47
|
+
{
|
|
48
|
+
type: 'select',
|
|
49
|
+
name: 'router',
|
|
50
|
+
message: '是否使用 vue-router?',
|
|
51
|
+
choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: 'select',
|
|
55
|
+
name: 'pinia',
|
|
56
|
+
message: '是否使用 Pinia(含持久化)?',
|
|
57
|
+
choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: 'select',
|
|
61
|
+
name: 'axios',
|
|
62
|
+
message: '是否使用 Axios?',
|
|
63
|
+
choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
type: 'select',
|
|
67
|
+
name: 'ui',
|
|
68
|
+
message: '请选择 UI 框架',
|
|
69
|
+
choices: [
|
|
70
|
+
{ title: 'Element Plus(PC)', value: 'element' },
|
|
71
|
+
{ title: 'Vant(Mobile)', value: 'vant' },
|
|
72
|
+
{ title: '不使用 UI 框架', value: 'none' }
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
// 3️⃣ 是否立即运行 dev
|
|
78
|
+
const { runDev } = await prompts({
|
|
79
|
+
type: 'select',
|
|
80
|
+
name: 'runDev',
|
|
81
|
+
message: '是否立即运行 npm run dev?',
|
|
82
|
+
choices: [{ title: 'Yes', value: true }, { title: 'No', value: false }]
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// 4️⃣ 拷贝 base 模板
|
|
86
|
+
const baseTemplate = language === 'ts' ? 'base-ts' : 'base-js'
|
|
87
|
+
fs.cpSync(
|
|
88
|
+
path.resolve(__dirname, `../template/${baseTemplate}`),
|
|
89
|
+
targetDir,
|
|
90
|
+
{ recursive: true }
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
// 4️⃣-1️⃣ 替换 index.html 的 title
|
|
94
|
+
const indexPath = path.join(targetDir, 'index.html')
|
|
95
|
+
if (fs.existsSync(indexPath)) {
|
|
96
|
+
const indexContent = fs.readFileSync(indexPath, 'utf-8')
|
|
97
|
+
fs.writeFileSync(
|
|
98
|
+
indexPath,
|
|
99
|
+
indexContent.replace(/<title>.*<\/title>/, `<title>${projectName}</title>`)
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 5️⃣ 拷贝可选模板
|
|
104
|
+
const copy = name => {
|
|
105
|
+
fs.cpSync(path.resolve(__dirname, `../template/${name}`), targetDir, { recursive: true })
|
|
106
|
+
}
|
|
107
|
+
features.router && copy(language === 'ts' ? 'router-ts' : 'router-js')
|
|
108
|
+
features.pinia && copy(language === 'ts' ? 'pinia-ts' : 'pinia-js')
|
|
109
|
+
features.axios && copy(language === 'ts' ? 'axios-ts' : 'axios-js')
|
|
110
|
+
|
|
111
|
+
// 6️⃣ 生成 main.js
|
|
112
|
+
const mainFile = language === 'ts' ? 'main.ts' : 'main.js'
|
|
113
|
+
const mainTplPath = path.join(targetDir, `src/${mainFile}.tpl`)
|
|
114
|
+
let main = fs.readFileSync(mainTplPath, 'utf-8')
|
|
115
|
+
|
|
116
|
+
const replacements = {
|
|
117
|
+
'/* __ROUTER_IMPORT__ */': features.router ? "import router from './router'" : '',
|
|
118
|
+
'/* __PINIA_IMPORT__ */': features.pinia
|
|
119
|
+
? "import { createPinia } from 'pinia'\nimport persistedstate from 'pinia-plugin-persistedstate'"
|
|
120
|
+
: '',
|
|
121
|
+
'/* __ELEMENT_IMPORT__ */': features.ui === 'element'
|
|
122
|
+
? `import ElementPlus from 'element-plus'
|
|
123
|
+
import 'element-plus/dist/index.css'
|
|
124
|
+
import * as ElementPlusIconsVue from '@element-plus/icons-vue'`
|
|
125
|
+
: '',
|
|
126
|
+
'/* __VANT_IMPORT__ */': features.ui === 'vant'
|
|
127
|
+
? `import Vant from 'vant'
|
|
128
|
+
import 'vant/lib/index.css'`
|
|
129
|
+
: '',
|
|
130
|
+
'/* __ROUTER_USE__ */': features.router ? 'app.use(router)' : '',
|
|
131
|
+
'/* __PINIA_USE__ */': features.pinia
|
|
132
|
+
? 'app.use(createPinia().use(persistedstate))'
|
|
133
|
+
: '',
|
|
134
|
+
'/* __ELEMENT_USE__ */': features.ui === 'element'
|
|
135
|
+
? `app.use(ElementPlus)
|
|
136
|
+
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
|
137
|
+
app.component(key, component)
|
|
138
|
+
}`
|
|
139
|
+
: '',
|
|
140
|
+
'/* __VANT_USE__ */': features.ui === 'vant'
|
|
141
|
+
? 'app.use(Vant)'
|
|
142
|
+
: ''
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function escapeRegExp (str) {
|
|
146
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for (const [placeholder, content] of Object.entries(replacements)) {
|
|
150
|
+
if (content) {
|
|
151
|
+
main = main.replace(placeholder, content)
|
|
152
|
+
} else {
|
|
153
|
+
const re = new RegExp(`^\\s*${escapeRegExp(placeholder)}\\s*$\\n?`, 'gm')
|
|
154
|
+
main = main.replace(re, '')
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
fs.writeFileSync(
|
|
159
|
+
path.join(targetDir, `src/${mainFile}`),
|
|
160
|
+
main
|
|
161
|
+
)
|
|
162
|
+
fs.unlinkSync(mainTplPath)
|
|
163
|
+
|
|
164
|
+
// 7️⃣ 生成 package.json
|
|
165
|
+
const pkgTpl = path.join(targetDir, 'package.json.tpl')
|
|
166
|
+
if (fs.existsSync(pkgTpl)) {
|
|
167
|
+
let pkg = fs.readFileSync(pkgTpl, 'utf-8')
|
|
168
|
+
|
|
169
|
+
const optionalDeps = {}
|
|
170
|
+
if (features.router) optionalDeps['vue-router'] = '^4.4.0'
|
|
171
|
+
if (features.pinia) {
|
|
172
|
+
optionalDeps['pinia'] = '^2.2.2'
|
|
173
|
+
optionalDeps['pinia-plugin-persistedstate'] = '^3.2.1'
|
|
174
|
+
}
|
|
175
|
+
if (features.axios) optionalDeps['axios'] = '^1.7.7'
|
|
176
|
+
if (features.ui === 'element') {
|
|
177
|
+
optionalDeps['element-plus'] = '^2.8.8'
|
|
178
|
+
optionalDeps['@element-plus/icons-vue'] = '^2.3.1'
|
|
179
|
+
}
|
|
180
|
+
if (features.ui === 'vant') {
|
|
181
|
+
optionalDeps['vant'] = '^4.9.22'
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let depsStr = ''
|
|
185
|
+
const keys = Object.keys(optionalDeps)
|
|
186
|
+
if (keys.length > 0) {
|
|
187
|
+
depsStr = ',\n' + keys.map(k => ` "${k}": "${optionalDeps[k]}"`).join(',\n')
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
pkg = pkg
|
|
191
|
+
.replace('__PROJECT_NAME__', projectName)
|
|
192
|
+
.replace('__OPTIONAL_DEP__', depsStr)
|
|
193
|
+
|
|
194
|
+
fs.writeFileSync(path.join(targetDir, 'package.json'), pkg)
|
|
195
|
+
fs.unlinkSync(pkgTpl)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 8️⃣ 安装依赖
|
|
199
|
+
console.log('📦 安装依赖中...')
|
|
200
|
+
execSync('npm install', { cwd: targetDir, stdio: 'inherit' })
|
|
201
|
+
|
|
202
|
+
// 9️⃣ 运行 dev
|
|
203
|
+
if (runDev) {
|
|
204
|
+
console.log('🚀 启动开发服务器...')
|
|
205
|
+
execSync('npm run dev', { cwd: targetDir, stdio: 'inherit' })
|
|
206
|
+
} else {
|
|
207
|
+
console.log(`\n✅ 项目创建完成\n👉 cd ${projectName}\n👉 npm run dev\n`)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
createProject()
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-vite-vue",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "基于Vite+Vue3创建基础项目模板",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"author": "YwaiX",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"create-vite-vue": "bin/index.js"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"vite",
|
|
17
|
+
"vue",
|
|
18
|
+
"js",
|
|
19
|
+
"ts",
|
|
20
|
+
"vue-router",
|
|
21
|
+
"pinia",
|
|
22
|
+
"axios"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"prompts": "^2.4.2"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
const service = axios.create({
|
|
4
|
+
baseURL: '/api',
|
|
5
|
+
timeout: 10000
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
service.interceptors.request.use(
|
|
9
|
+
config => config,
|
|
10
|
+
error => Promise.reject(error)
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
service.interceptors.response.use(
|
|
14
|
+
response => response.data,
|
|
15
|
+
error => Promise.reject(error)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
export default service
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
const service = axios.create({
|
|
4
|
+
baseURL: '/api',
|
|
5
|
+
timeout: 10000
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
service.interceptors.request.use(
|
|
9
|
+
config => config,
|
|
10
|
+
error => Promise.reject(error)
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
service.interceptors.response.use(
|
|
14
|
+
response => response.data,
|
|
15
|
+
error => Promise.reject(error)
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
export default service
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Vite + Vue3 + js + vue-router + pinia + element-plus + axios + less
|
|
2
|
+
|
|
3
|
+
本项目基于Vite + Vue3 + js + vue-router + pinia + element-plus + axios + less创建
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
运行方式
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
cd my-project
|
|
11
|
+
npm i
|
|
12
|
+
npm run dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
需要修改的地方
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
utils/request.js
|
|
21
|
+
router/index.js
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
可以修改的地方
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
vite.config.js
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
该文件中的`server.proxy`,`server.host`,`server.port`可以进行更改,其他地方不建议更改
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>vue-template-js</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.js"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"less": "^4.5.1",
|
|
13
|
+
"tslib": "^2.8.1",
|
|
14
|
+
"vue": "^3.5.24"__OPTIONAL_DEP__
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
18
|
+
"vite": "npm:rolldown-vite@7.2.5"
|
|
19
|
+
},
|
|
20
|
+
"overrides": {
|
|
21
|
+
"vite": "npm:rolldown-vite@7.2.5"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="welcome-container">
|
|
3
|
+
<div class="welcome-card">
|
|
4
|
+
<h1 class="welcome-title">欢迎来到我的项目!</h1>
|
|
5
|
+
<p class="welcome-desc">
|
|
6
|
+
这是一个 Vue 3 + JS 版基础项目的欢迎页面示例。
|
|
7
|
+
</p>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<style scoped>
|
|
18
|
+
/* 外层容器,全屏居中 */
|
|
19
|
+
.welcome-container {
|
|
20
|
+
width: 100vw;
|
|
21
|
+
height: 100vh;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
background: linear-gradient(135deg, #4facfe, #00f2fe);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* 卡片样式 */
|
|
29
|
+
.welcome-card {
|
|
30
|
+
background-color: rgba(255, 255, 255, 0.9);
|
|
31
|
+
padding: 40px;
|
|
32
|
+
border-radius: 16px;
|
|
33
|
+
text-align: center;
|
|
34
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
35
|
+
animation: fadeIn 1s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* 标题 */
|
|
39
|
+
.welcome-title {
|
|
40
|
+
font-size: 2.5rem;
|
|
41
|
+
margin-bottom: 20px;
|
|
42
|
+
color: #333;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* 描述 */
|
|
46
|
+
.welcome-desc {
|
|
47
|
+
font-size: 1.2rem;
|
|
48
|
+
margin-bottom: 30px;
|
|
49
|
+
color: #555;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* 标题淡入动画 */
|
|
53
|
+
@keyframes fadeIn {
|
|
54
|
+
from {
|
|
55
|
+
opacity: 0;
|
|
56
|
+
transform: translateY(-20px);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
to {
|
|
60
|
+
opacity: 1;
|
|
61
|
+
transform: translateY(0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import App from './App.vue'
|
|
3
|
+
import './style.css'
|
|
4
|
+
/* __ELEMENT_IMPORT__ */
|
|
5
|
+
/* __ROUTER_IMPORT__ */
|
|
6
|
+
/* __PINIA_IMPORT__ */
|
|
7
|
+
/* __VANT_IMPORT__ */
|
|
8
|
+
|
|
9
|
+
const app = createApp(App)
|
|
10
|
+
|
|
11
|
+
/* __ELEMENT_USE__ */
|
|
12
|
+
/* __ROUTER_USE__ */
|
|
13
|
+
/* __PINIA_USE__ */
|
|
14
|
+
/* __VANT_USE__ */
|
|
15
|
+
|
|
16
|
+
app.mount('#app')
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.el-header,
|
|
7
|
+
.el-footer {
|
|
8
|
+
background-color: #B3C0D1;
|
|
9
|
+
color: #333;
|
|
10
|
+
text-align: center;
|
|
11
|
+
line-height: 60px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.el-aside {
|
|
15
|
+
background-color: #D3DCE6;
|
|
16
|
+
color: #333;
|
|
17
|
+
text-align: center;
|
|
18
|
+
line-height: 200px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.el-main {
|
|
22
|
+
background-color: #E9EEF3;
|
|
23
|
+
color: #333;
|
|
24
|
+
text-align: center;
|
|
25
|
+
line-height: 160px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
body>.el-container {
|
|
29
|
+
margin-bottom: 40px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.el-container:nth-child(5) .el-aside,
|
|
33
|
+
.el-container:nth-child(6) .el-aside {
|
|
34
|
+
line-height: 260px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.el-container:nth-child(7) .el-aside {
|
|
38
|
+
line-height: 320px;
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import vue from '@vitejs/plugin-vue'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { defineConfig } from 'vite'
|
|
4
|
+
|
|
5
|
+
// https://vite.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [vue()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
'@': path.resolve(__dirname, './src')
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
server: {
|
|
14
|
+
host: '0.0.0.0',
|
|
15
|
+
port: 20000,
|
|
16
|
+
strictPort: false,
|
|
17
|
+
proxy: {
|
|
18
|
+
'/api': {
|
|
19
|
+
target: 'http://localhost:8080',
|
|
20
|
+
changeOrigin: true,
|
|
21
|
+
rewrite: path => path.replace(/^\/api/, '')
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Vite + Vue3 + ts + vue-router + pinia + element-plus + axios + less
|
|
2
|
+
|
|
3
|
+
本项目基于Vite + Vue3 + ts + vue-router + pinia + element-plus + axios + less创建
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
运行方式
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
cd my-project
|
|
11
|
+
npm i
|
|
12
|
+
npm run dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
需要修改的地方
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
utils/request.ts
|
|
21
|
+
router/index.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
可以修改的地方
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
vite.config.ts
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
该文件中的`server.proxy`,`server.host`,`server.port`可以进行更改,其他地方不建议更改
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>vue-template-ts</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app"></div>
|
|
11
|
+
<script type="module" src="/src/main.ts"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "__PROJECT_NAME__",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vue-tsc -b && vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"less": "^4.5.1",
|
|
13
|
+
"tslib": "^2.8.1",
|
|
14
|
+
"vue": "^3.5.24"__OPTIONAL_DEP__
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^24.10.4",
|
|
18
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
19
|
+
"@vue/tsconfig": "^0.8.1",
|
|
20
|
+
"typescript": "~5.9.3",
|
|
21
|
+
"vite": "npm:rolldown-vite@7.2.5",
|
|
22
|
+
"vue-tsc": "^3.1.4"
|
|
23
|
+
},
|
|
24
|
+
"overrides": {
|
|
25
|
+
"vite": "npm:rolldown-vite@7.2.5"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="welcome-container">
|
|
3
|
+
<div class="welcome-card">
|
|
4
|
+
<h1 class="welcome-title">欢迎来到我的项目!</h1>
|
|
5
|
+
<p class="welcome-desc">
|
|
6
|
+
这是一个 Vue 3 + TS 版基础项目的欢迎页面示例。
|
|
7
|
+
</p>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<style scoped>
|
|
18
|
+
/* 外层容器,全屏居中 */
|
|
19
|
+
.welcome-container {
|
|
20
|
+
width: 100vw;
|
|
21
|
+
height: 100vh;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
background: linear-gradient(135deg, #4facfe, #00f2fe);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* 卡片样式 */
|
|
29
|
+
.welcome-card {
|
|
30
|
+
background-color: rgba(255, 255, 255, 0.9);
|
|
31
|
+
padding: 40px;
|
|
32
|
+
border-radius: 16px;
|
|
33
|
+
text-align: center;
|
|
34
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
35
|
+
animation: fadeIn 1s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* 标题 */
|
|
39
|
+
.welcome-title {
|
|
40
|
+
font-size: 2.5rem;
|
|
41
|
+
margin-bottom: 20px;
|
|
42
|
+
color: #333;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* 描述 */
|
|
46
|
+
.welcome-desc {
|
|
47
|
+
font-size: 1.2rem;
|
|
48
|
+
margin-bottom: 30px;
|
|
49
|
+
color: #555;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* 标题淡入动画 */
|
|
53
|
+
@keyframes fadeIn {
|
|
54
|
+
from {
|
|
55
|
+
opacity: 0;
|
|
56
|
+
transform: translateY(-20px);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
to {
|
|
60
|
+
opacity: 1;
|
|
61
|
+
transform: translateY(0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import App from './App.vue'
|
|
3
|
+
import './style.css'
|
|
4
|
+
/* __ELEMENT_IMPORT__ */
|
|
5
|
+
/* __ROUTER_IMPORT__ */
|
|
6
|
+
/* __PINIA_IMPORT__ */
|
|
7
|
+
/* __VANT_IMPORT__ */
|
|
8
|
+
|
|
9
|
+
const app = createApp(App)
|
|
10
|
+
|
|
11
|
+
/* __ELEMENT_USE__ */
|
|
12
|
+
/* __ROUTER_USE__ */
|
|
13
|
+
/* __PINIA_USE__ */
|
|
14
|
+
/* __VANT_USE__ */
|
|
15
|
+
|
|
16
|
+
app.mount('#app')
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.el-header,
|
|
7
|
+
.el-footer {
|
|
8
|
+
background-color: #B3C0D1;
|
|
9
|
+
color: #333;
|
|
10
|
+
text-align: center;
|
|
11
|
+
line-height: 60px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.el-aside {
|
|
15
|
+
background-color: #D3DCE6;
|
|
16
|
+
color: #333;
|
|
17
|
+
text-align: center;
|
|
18
|
+
line-height: 200px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.el-main {
|
|
22
|
+
background-color: #E9EEF3;
|
|
23
|
+
color: #333;
|
|
24
|
+
text-align: center;
|
|
25
|
+
line-height: 160px;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
body>.el-container {
|
|
29
|
+
margin-bottom: 40px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.el-container:nth-child(5) .el-aside,
|
|
33
|
+
.el-container:nth-child(6) .el-aside {
|
|
34
|
+
line-height: 260px;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.el-container:nth-child(7) .el-aside {
|
|
38
|
+
line-height: 320px;
|
|
39
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
5
|
+
"types": ["vite/client"],
|
|
6
|
+
|
|
7
|
+
/* Linting */
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUnusedLocals": true,
|
|
10
|
+
"noUnusedParameters": true,
|
|
11
|
+
"erasableSyntaxOnly": true,
|
|
12
|
+
"noFallthroughCasesInSwitch": true,
|
|
13
|
+
"noUncheckedSideEffectImports": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"baseUrl": "./",
|
|
4
|
+
"paths": {
|
|
5
|
+
"@/*": [
|
|
6
|
+
"./src/*"
|
|
7
|
+
]
|
|
8
|
+
},
|
|
9
|
+
"module": "esnext",
|
|
10
|
+
"target": "esnext",
|
|
11
|
+
"moduleResolution": "node",
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"src/**/*.ts",
|
|
15
|
+
"src/**/*.tsx",
|
|
16
|
+
"src/**/*.vue",
|
|
17
|
+
"tests/**/*.ts",
|
|
18
|
+
"tests/**/*.tsx",
|
|
19
|
+
"typings",
|
|
20
|
+
"src/.env"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
4
|
+
"target": "ES2023",
|
|
5
|
+
"lib": ["ES2023"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
|
|
10
|
+
/* Bundler mode */
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"allowImportingTsExtensions": true,
|
|
13
|
+
"verbatimModuleSyntax": true,
|
|
14
|
+
"moduleDetection": "force",
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
/* Linting */
|
|
18
|
+
"strict": true,
|
|
19
|
+
"noUnusedLocals": true,
|
|
20
|
+
"noUnusedParameters": true,
|
|
21
|
+
"erasableSyntaxOnly": true,
|
|
22
|
+
"noFallthroughCasesInSwitch": true,
|
|
23
|
+
"noUncheckedSideEffectImports": true
|
|
24
|
+
},
|
|
25
|
+
"include": ["vite.config.ts"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import vue from '@vitejs/plugin-vue'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import { defineConfig } from 'vite'
|
|
4
|
+
|
|
5
|
+
// https://vite.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [vue()],
|
|
8
|
+
resolve: {
|
|
9
|
+
alias: {
|
|
10
|
+
'@': path.resolve(__dirname, './src')
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
server: {
|
|
14
|
+
host: '0.0.0.0',
|
|
15
|
+
port: 20000,
|
|
16
|
+
strictPort: false,
|
|
17
|
+
proxy: {
|
|
18
|
+
'/api': {
|
|
19
|
+
target: 'http://localhost:8080',
|
|
20
|
+
changeOrigin: true,
|
|
21
|
+
rewrite: (path) => path.replace(/^\/api/, '')
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
})
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="welcome-container">
|
|
3
|
+
<div class="welcome-card">
|
|
4
|
+
<h1 class="welcome-title">欢迎来到我的项目!</h1>
|
|
5
|
+
<p class="welcome-desc">
|
|
6
|
+
这是一个 Vue 3 + JS 版基础项目的欢迎页面示例。
|
|
7
|
+
</p>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup>
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<style scoped>
|
|
18
|
+
/* 外层容器,全屏居中 */
|
|
19
|
+
.welcome-container {
|
|
20
|
+
width: 100vw;
|
|
21
|
+
height: 100vh;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
background: linear-gradient(135deg, #4facfe, #00f2fe);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* 卡片样式 */
|
|
29
|
+
.welcome-card {
|
|
30
|
+
background-color: rgba(255, 255, 255, 0.9);
|
|
31
|
+
padding: 40px;
|
|
32
|
+
border-radius: 16px;
|
|
33
|
+
text-align: center;
|
|
34
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
35
|
+
animation: fadeIn 1s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* 标题 */
|
|
39
|
+
.welcome-title {
|
|
40
|
+
font-size: 2.5rem;
|
|
41
|
+
margin-bottom: 20px;
|
|
42
|
+
color: #333;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* 描述 */
|
|
46
|
+
.welcome-desc {
|
|
47
|
+
font-size: 1.2rem;
|
|
48
|
+
margin-bottom: 30px;
|
|
49
|
+
color: #555;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* 标题淡入动画 */
|
|
53
|
+
@keyframes fadeIn {
|
|
54
|
+
from {
|
|
55
|
+
opacity: 0;
|
|
56
|
+
transform: translateY(-20px);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
to {
|
|
60
|
+
opacity: 1;
|
|
61
|
+
transform: translateY(0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="welcome-container">
|
|
3
|
+
<div class="welcome-card">
|
|
4
|
+
<h1 class="welcome-title">欢迎来到我的项目!</h1>
|
|
5
|
+
<p class="welcome-desc">
|
|
6
|
+
这是一个 Vue 3 + TS 版基础项目的欢迎页面示例。
|
|
7
|
+
</p>
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<style scoped>
|
|
18
|
+
/* 外层容器,全屏居中 */
|
|
19
|
+
.welcome-container {
|
|
20
|
+
width: 100vw;
|
|
21
|
+
height: 100vh;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
background: linear-gradient(135deg, #4facfe, #00f2fe);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* 卡片样式 */
|
|
29
|
+
.welcome-card {
|
|
30
|
+
background-color: rgba(255, 255, 255, 0.9);
|
|
31
|
+
padding: 40px;
|
|
32
|
+
border-radius: 16px;
|
|
33
|
+
text-align: center;
|
|
34
|
+
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
|
|
35
|
+
animation: fadeIn 1s ease;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* 标题 */
|
|
39
|
+
.welcome-title {
|
|
40
|
+
font-size: 2.5rem;
|
|
41
|
+
margin-bottom: 20px;
|
|
42
|
+
color: #333;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* 描述 */
|
|
46
|
+
.welcome-desc {
|
|
47
|
+
font-size: 1.2rem;
|
|
48
|
+
margin-bottom: 30px;
|
|
49
|
+
color: #555;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* 标题淡入动画 */
|
|
53
|
+
@keyframes fadeIn {
|
|
54
|
+
from {
|
|
55
|
+
opacity: 0;
|
|
56
|
+
transform: translateY(-20px);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
to {
|
|
60
|
+
opacity: 1;
|
|
61
|
+
transform: translateY(0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
</style>
|