@aibai/create-myvue 0.0.2 → 0.0.5

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/cli.js CHANGED
@@ -4,6 +4,17 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const inquirer = require('inquirer');
6
6
 
7
+ // 读取模板文件内容
8
+ function readTemplateFile(templatePath) {
9
+ try {
10
+ const fullPath = path.join(__dirname, '../templates', templatePath);
11
+ return fs.readFileSync(fullPath, 'utf8').trim();
12
+ } catch (error) {
13
+ console.error(`Error reading template file ${templatePath}: ${error.message}`);
14
+ return '';
15
+ }
16
+ }
17
+
7
18
  // 插件配置
8
19
  const plugins = [
9
20
  {
@@ -12,27 +23,8 @@ const plugins = [
12
23
  dependencies: ['unplugin-auto-import'],
13
24
  config: {
14
25
  vite: {
15
- imports: [`import AutoImport from 'unplugin-auto-import/vite'`],
16
- plugins: [
17
- `AutoImport({
18
- include: [
19
- /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
20
- /\.vue$/,
21
- /\.vue\?vue/ // .vue
22
- ],
23
- imports: [
24
- 'vue',
25
- 'vue-router',
26
- 'pinia'
27
- ],
28
- dts: 'src/types/auto-import.d.ts',
29
- eslintrc: {
30
- enabled: true,
31
- filepath: './.eslintrc-auto-import.json',
32
- globalsPropValue: true,
33
- },
34
- }),`
35
- ]
26
+ imports: [readTemplateFile('plugins/unplugin-auto-import/import.js')],
27
+ plugins: [readTemplateFile('plugins/unplugin-auto-import/plugin.js')]
36
28
  }
37
29
  }
38
30
  },
@@ -42,15 +34,8 @@ const plugins = [
42
34
  dependencies: ['unplugin-vue-components'],
43
35
  config: {
44
36
  vite: {
45
- imports: [`import Components from 'unplugin-vue-components/vite'`],
46
- plugins: [
47
- `Components({
48
- dirs: ['src/components'],
49
- extensions: ['vue'],
50
- dts: 'src/types/auto-components.d.ts',
51
- resolvers: []
52
- }),`
53
- ]
37
+ imports: [readTemplateFile('plugins/unplugin-vue-components/import.js')],
38
+ plugins: [readTemplateFile('plugins/unplugin-vue-components/plugin.js')]
54
39
  }
55
40
  }
56
41
  },
@@ -60,36 +45,17 @@ const plugins = [
60
45
  dependencies: ['unocss'],
61
46
  config: {
62
47
  vite: {
63
- imports: [`import UnoCSS from 'unocss/vite'`],
64
- plugins: [
65
- `UnoCSS()`
66
- ]
48
+ imports: [readTemplateFile('plugins/unocss/import.js')],
49
+ plugins: [readTemplateFile('plugins/unocss/plugin.js')]
67
50
  },
68
51
  files: [
69
52
  {
70
53
  path: 'uno.config.ts',
71
- content: `
72
- import { defineConfig, transformerDirectives, transformerVariantGroup } from 'unocss'
73
-
74
- export default defineConfig({theme: {
75
- colors: {
76
- primary: 'var(--primary-color)',
77
- },
78
- },
79
- shortcuts: {
80
- 'content': 'relative max-w-[1024px] mx-auto',
81
- 'btn': '',
82
- },
83
- transformers: [
84
- transformerDirectives(),
85
- transformerVariantGroup()
86
- ]
87
- })
88
- `
54
+ content: readTemplateFile('plugins/unocss/uno.config.ts')
89
55
  },
90
56
  {
91
57
  path: 'src/main.js',
92
- content: "import 'virtual:uno.css';\n",
58
+ content: readTemplateFile('plugins/unocss/files/main.js') + '\n',
93
59
  append: true
94
60
  }
95
61
  ]
@@ -101,52 +67,17 @@ const plugins = [
101
67
  dependencies: ['vite-plugin-svg-icons'],
102
68
  config: {
103
69
  vite: {
104
- imports: [`import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'`],
105
- plugins: [
106
- `createSvgIconsPlugin({
107
- // 指定需要缓存的图标文件夹
108
- iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
109
- // 指定symbolId格式
110
- symbolId: 'icon-[dir]-[name]',
111
- }),`
112
- ]
70
+ imports: [readTemplateFile('plugins/vite-plugin-svg-icons/import.js')],
71
+ plugins: [readTemplateFile('plugins/vite-plugin-svg-icons/plugin.js')]
113
72
  },
114
73
  files: [
115
74
  {
116
75
  path: 'src/components/Icon.vue',
117
- content: `
118
- <script setup lang="ts">
119
- import { computed } from 'vue';
120
-
121
- const props = defineProps({
122
- prefix: { type: String, default: 'icon', },
123
- iconName: { type: String, required: true, },
124
- color: { type: String, default: '' }
125
- })
126
-
127
- const symbolId = computed(() => '#' + props.prefix + '-' + props.iconName);
128
- </script>
129
-
130
- <template>
131
- <svg aria-hidden="true" class="svg-icon">
132
- <use :xlink:href="symbolId" :fill="color" />
133
- </svg>
134
- </template>
135
-
136
- <style>
137
- .svg-icon {
138
- width: 1em;
139
- height: 1em;
140
- vertical-align: -0.15em;
141
- overflow: hidden;
142
- fill: currentColor;
143
- }
144
- </style>
145
- `
76
+ content: readTemplateFile('plugins/vite-plugin-svg-icons/files/Icon.vue')
146
77
  },
147
78
  {
148
79
  path: 'src/main.js',
149
- content: "import 'virtual:svg-icons-register';\n",
80
+ content: readTemplateFile('plugins/vite-plugin-svg-icons/files/main.js') + '\n',
150
81
  append: true
151
82
  }
152
83
  ]
@@ -160,673 +91,27 @@ const plugins = [
160
91
  files: [
161
92
  {
162
93
  path: 'src/utils/axiosConfig.ts',
163
- content: `
164
- // axios 配置文件
165
- // 定义全局axios配置,包括基础URL、超时时间、响应格式验证等
166
-
167
- // API基础URL,使用相对路径以便通过Vite代理转发
168
- export const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://110.41.59.11/api';
169
- // 注意:请勿使用绝对URL,否则会绕过Vite代理
170
-
171
- // 请求超时时间(毫秒)
172
- export const REQUEST_TIMEOUT = 40000;
173
-
174
- // 响应数据格式验证
175
- export const validateResponseFormat = (data: unknown): boolean => {
176
- return typeof data === 'object' && data !== null;
177
- };
178
-
179
- // 错误消息映射
180
- export const errorMessageMap: Record<number, string> = {
181
- 400: '请求参数错误',
182
- 401: '未授权,请重新登录',
183
- 403: '拒绝访问',
184
- 404: '请求的资源不存在',
185
- 405: '请求方法不允许',
186
- 500: '服务器内部错误',
187
- 502: '网关错误',
188
- 503: '服务不可用',
189
- 504: '网关超时',
190
- };
191
-
192
- `
94
+ content: readTemplateFile('plugins/axios/files/axiosConfig.ts')
193
95
  },
194
96
  {
195
97
  path: 'src/utils/axiosInstance.ts',
196
- content: `
197
- // axios 实例封装
198
- import axios, { type AxiosRequestConfig, type AxiosError } from 'axios';
199
- import { API_BASE_URL, REQUEST_TIMEOUT } from './axiosConfig';
200
- import { handleAxiosError, isBusinessError, formatBusinessError } from './errorHandler';
201
-
202
- interface HttpResponse<T = unknown> {
203
- code: number;
204
- msg: string;
205
- data: T;
206
- }
207
-
208
- // 创建axios实例
209
- const http = axios.create({
210
- baseURL: API_BASE_URL,
211
- timeout: REQUEST_TIMEOUT,
212
- headers: {
213
- 'Content-Type': 'application/json;charset=UTF-8',
214
- },
215
- });
216
-
217
- // 请求拦截器
218
- http.interceptors.request.use(
219
- (config) => {
220
- config.headers = config.headers || {};
221
- // 从本地存储获取token
222
- const token = localStorage.getItem('APP_TOKEN');
223
- // 如果存在token,则添加到请求头
224
- if (token) {
225
- config.headers = config.headers || {};
226
- config.headers['x-token'] = token;
227
- }
228
- return config;
229
- },
230
- (error) => {
231
- // 请求错误处理
232
- console.error('请求配置错误:', error);
233
- return Promise.reject(error);
234
- }
235
- );
236
-
237
- // 响应拦截器
238
- http.interceptors.response.use(
239
- (response) => {
240
- const data = response.data;
241
-
242
- // 检查是否为业务错误
243
- if (isBusinessError(data)) {
244
- const businessError = formatBusinessError(data);
245
- // globalErrorHandler(businessError);
246
- return Promise.reject(businessError);
247
- }
248
-
249
- // 直接返回响应数据
250
- return data.data;
251
- },
252
- (error: AxiosError) => {
253
- // 处理HTTP错误
254
- const apiError = handleAxiosError(error);
255
- // globalErrorHandler(apiError);
256
- return Promise.reject(apiError);
257
- }
258
- );
259
-
260
- // 导出http实例
261
- export default http;
262
-
263
- // 导出常用的请求方法
264
- export const request = {
265
- // 使用类型断言来匹配响应拦截器实际返回的data.data
266
- get: <T = unknown>(url: string, config?: AxiosRequestConfig) => http.get<HttpResponse<T>>(url, config) as unknown as Promise<T>,
267
- post: <T = unknown>(url: string, data?: unknown, config?: AxiosRequestConfig) => http.post<HttpResponse<T>>(url, data, config) as unknown as Promise<T>,
268
- // 导出axios引用,用于取消请求等高级功能
269
- axios: axios
270
- };
271
-
272
- `
98
+ content: readTemplateFile('plugins/axios/files/axiosInstance.ts')
273
99
  },
274
100
  {
275
101
  path: 'src/utils/errorHandler.ts',
276
- content: `
277
- // 错误处理工具
278
- import type { AxiosError } from 'axios';
279
- import { errorMessageMap } from './axiosConfig';
280
-
281
- // 错误类型接口
282
- export interface ApiError extends Error {
283
- code?: number;
284
- msg?: string;
285
- data?: unknown;
286
- }
287
-
288
- /**
289
- * 创建API错误对象
290
- * @param message 错误消息
291
- * @param status 状态码
292
- * @param code 错误代码
293
- * @param data 错误数据
294
- * @returns ApiError对象
295
- */
296
- export function createApiError<T>(message: string, code?: number, data?: T): ApiError {
297
- const error = new Error(message) as ApiError;
298
- error.msg = message;
299
- error.code = code;
300
- error.data = data;
301
- return error;
302
- }
303
-
304
- /**
305
- * 处理axios错误
306
- * @param error axios错误对象
307
- * @returns 标准化的ApiError
308
- */
309
- export function handleAxiosError<T>(error: AxiosError): ApiError {
310
- // 网络错误
311
- if (!error.response) {
312
- return createApiError('网络错误,请检查您的网络连接', -1);
313
- }
314
-
315
- const { response } = error;
316
- const status = response.status;
317
-
318
- // 从响应数据中提取错误信息
319
- const responseData = response.data;
320
- // 安全地访问响应数据
321
- const data = responseData as Record<string, T>;
322
- const errorMessage = data?.msg as string ||
323
- errorMessageMap[status] ||
324
- \`请求失败,状态码: ${status}\`;
325
-
326
- const errorCode = data?.code as number || status;
327
-
328
- return createApiError(errorMessage, errorCode, responseData);
329
- }
330
-
331
- /**
332
- * 处理业务错误
333
- * @param data 响应数据
334
- * @returns 是否为业务错误
335
- */
336
- export function isBusinessError(data: unknown): boolean {
337
- // 这里根据后端返回的业务错误格式进行判断
338
- return data != null && typeof data === 'object' && 'code' in data && data.code !== 0;
339
- }
340
-
341
- /**
342
- * 格式化业务错误
343
- * @param data 响应数据
344
- * @returns ApiError对象
345
- */
346
- export function formatBusinessError<T>(data: T): ApiError {
347
- const businessData = data as Record<string, T>;
348
- return createApiError(
349
- (businessData?.msg as string) || '业务处理失败',
350
- (businessData?.code as number) || 400,
351
- data
352
- );
353
- }
354
-
355
- /**
356
- * 全局错误处理器
357
- * 可以在这里添加错误日志记录、上报等功能
358
- * @param error 错误对象
359
- */
360
- export function globalErrorHandler(error: Error | ApiError): void {
361
- console.error('Global Error:', error);
362
-
363
- // 可以在这里添加错误上报逻辑
364
- // 例如:上报到Sentry等错误监控服务
365
- // reportErrorToSentry(error);
366
-
367
- // 根据错误类型进行不同处理
368
- // if ('code' in error && error.code === 401) {
369
- // // 处理未授权错误,如跳转到登录页
370
- // handleUnauthorizedError();
371
- // }
372
- }
373
-
374
- /**
375
- * 处理未授权错误
376
- */
377
- // function handleUnauthorizedError(): void {
378
- // // 清除本地存储的token
379
- // localStorage.removeItem('token');
380
-
381
- // // 可以在这里添加跳转到登录页的逻辑
382
- // // 注意:由于这是工具函数,避免直接操作Vue Router
383
- // // 实际使用时,应该在组件或业务逻辑中处理跳转
384
- // console.warn('用户未授权,请重新登录');
385
- // }
386
-
387
- `
102
+ content: readTemplateFile('plugins/axios/files/errorHandler.ts')
388
103
  },
389
104
  {
390
105
  path: 'src/utils/imageUtils.ts',
391
- content: `
392
- // 图片地址处理工具函数
393
-
394
- // 导出默认的图片基础URL配置(可以从环境变量读取)
395
- export const DEFAULT_IMAGE_BASE_URL = import.meta.env.VITE_IMAGE_BASE_URL || '';
396
-
397
- /**
398
- * 图片地址拼接函数
399
- * @param baseUrl 基础图片域名或路径
400
- * @param imagePath 图片相对路径
401
- * @returns 完整的图片URL
402
- */
403
- export const joinImageUrl = (imagePath: string, baseUrl?: string): string => {
404
- // 处理空值情况
405
- if (!imagePath) return '';
406
-
407
- // 如果imagePath已经是完整的URL(包含http或https),直接返回
408
- if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
409
- return imagePath;
410
- }
411
-
412
- // 如果baseUrl未提供,使用默认值
413
- const newBaseUrl = baseUrl || DEFAULT_IMAGE_BASE_URL;
414
-
415
- // 处理baseUrl结尾的斜杠和imagePath开头的斜杠,避免重复
416
- const normalizedBaseUrl = newBaseUrl.endsWith('/') ? newBaseUrl.slice(0, -1) : newBaseUrl;
417
- let normalizedImagePath = imagePath.startsWith('/') ? imagePath.slice(1) : imagePath;
418
- // 判断链接开头是否包含 '/api'前缀,包含则删除
419
- if (normalizedImagePath.startsWith('api/')) {
420
- normalizedImagePath = normalizedImagePath.slice(4);
421
- }
422
- // 拼接完整URL
423
- return \`${normalizedBaseUrl}/${normalizedImagePath}\`;
424
- };
425
-
426
- /**
427
- * 批量拼接图片URL
428
- * @param baseUrl 基础图片域名或路径
429
- * @param imagePaths 图片相对路径数组
430
- * @returns 完整图片URL数组
431
- */
432
- export const joinImageUrls = (imagePaths: string[], baseUrl?: string): string[] => {
433
- return imagePaths.map(path => joinImageUrl(path, baseUrl));
434
- };
435
-
436
- /**
437
- * Vue组件:图片URL拼接工具
438
- * 可以在模板中直接使用
439
- */
440
- export const useImageUrl = () => {
441
-
442
- return {
443
- // 单个图片URL拼接
444
- getImageUrl: (imagePath: string, customBaseUrl?: string) => {
445
- return joinImageUrl(imagePath, customBaseUrl);
446
- },
447
-
448
- // 批量图片URL拼接
449
- getImageUrls: (imagePaths: string[], customBaseUrl?: string) => {
450
- return joinImageUrls(imagePaths, customBaseUrl);
451
- }
452
- };
453
- };
454
- `
106
+ content: readTemplateFile('plugins/axios/files/imageUtils.ts')
455
107
  },
456
108
  {
457
109
  path: 'src/utils/README.md',
458
- content: `
459
- # Axios 二次封装说明
460
-
461
- ## 项目结构
462
-
463
- \`\`\`
464
- /src/utils/
465
- ├── axiosConfig.ts # axios 配置文件
466
- ├── axiosInstance.ts # axios 实例封装
467
- ├── errorHandler.ts # 错误处理工具
468
- ├── axiosExample.ts # 使用示例
469
- └── README.md # 说明文档
470
-
471
- /src/api/
472
- ├── index.ts # API管理入口
473
- ├── userApi.ts # 用户相关API
474
- └── commonApi.ts # 通用API
475
- \`\`\`
476
-
477
- ## 功能特性
478
-
479
- 1. **统一配置管理**:通过\`axiosConfig.ts\`集中管理API基础URL、超时时间等配置
480
- 2. **请求拦截器**:自动添加token认证、时间戳防缓存
481
- 3. **响应拦截器**:统一处理响应数据格式和错误
482
- 4. **错误处理机制**:HTTP错误、业务错误统一处理,支持错误日志上报
483
- 5. **API模块化管理**:按业务模块划分API接口,方便维护
484
- 6. **TypeScript支持**:完整的类型定义,提供良好的开发体验
485
- 7. **文件上传支持**:简化文件上传操作
486
- 8. **取消请求支持**:支持取消正在进行的请求
487
-
488
- ## 安装和配置
489
-
490
- 项目已安装axios依赖,如需手动安装:
491
-
492
- \`\`\`bash
493
- pnpm install axios
494
- \`\`\`
495
-
496
- ### 环境变量配置
497
-
498
- 在项目根目录创建`.env`文件,配置API基础URL:
499
-
500
- \`\`\`
501
- VITE_API_BASE_URL=https://your-api-domain.com/api
502
- \`\`\`
503
-
504
- ## 使用方法
505
-
506
- ### 1. 导入方式
507
-
508
- \`\`\`typescript
509
- // 方式1:导入API模块(推荐)
510
- import { api } from '@/api';
511
-
512
- // 方式2:直接使用request工具函数
513
- import { request } from '@/api';
514
-
515
- // 方式3:导入原始axios实例
516
- import { http } from '@/api';
517
- \`\`\`
518
-
519
- ### 2. 基本使用示例
520
-
521
- #### 用户登录
522
-
523
- \`\`\`typescript
524
- async function login() {
525
- try {
526
- const result = await api.user.login({
527
- username: 'admin',
528
- password: '123456'
529
- });
530
-
531
- // 保存token
532
- localStorage.setItem('token', result.token);
533
- console.log('登录成功');
534
- } catch (error) {
535
- console.error('登录失败:', error.message);
536
- }
537
- }
538
- \`\`\`
539
-
540
- #### 获取用户信息
541
-
542
- \`\`\`typescript
543
- async function getUserInfo() {
544
- try {
545
- const userInfo = await api.user.getUserInfo();
546
- console.log('用户信息:', userInfo);
547
- } catch (error) {
548
- console.error('获取用户信息失败:', error);
549
- }
550
- }
551
- \`\`\`
552
-
553
- #### 通用请求方法
554
-
555
- \`\`\`typescript
556
- // GET请求
557
- const data = await request.get('/api/data', {
558
- params: { id: 123 },
559
- timeout: 5000
560
- });
561
-
562
- // POST请求
563
- const result = await request.post('/api/data', {
564
- name: 'test',
565
- value: 'example'
566
- });
567
-
568
- // PUT请求
569
- await request.put('/api/data/123', { name: 'updated' });
570
-
571
- // DELETE请求
572
- await request.delete('/api/data/123');
573
- \`\`\`
574
-
575
- ### 3. 文件上传示例
576
-
577
- \`\`\`typescript
578
- async function uploadAvatar(file: File) {
579
- try {
580
- const result = await api.common.uploadFile(file, 'image');
581
- console.log('上传成功,文件URL:', result.url);
582
- return result.url;
583
- } catch (error) {
584
- console.error('上传失败:', error);
585
- return null;
586
- }
587
- }
588
- \`\`\`
589
-
590
- ### 4. 错误处理
591
-
592
- \`\`\`typescript
593
- import { api, ApiError } from '@/api';
594
-
595
- async function handleRequest() {
596
- try {
597
- await api.user.getUserInfo();
598
- } catch (error) {
599
- if (error instanceof ApiError) {
600
- // 根据错误状态码处理
601
- if (error.status === 401) {
602
- // 未授权,跳转到登录页
603
- console.log('请重新登录');
604
- } else if (error.status === 403) {
605
- console.log('没有权限访问');
606
- } else {
607
- console.log('其他错误:', error.message);
608
- }
609
-
610
- // 根据错误代码处理
611
- if (error.code === 'USER_NOT_FOUND') {
612
- console.log('用户不存在');
613
- }
614
- }
615
- }
616
- }
617
- \`\`\`
618
-
619
- ### 5. 并发请求
620
-
621
- \`\`\`typescript
622
- async function fetchMultipleData() {
623
- try {
624
- const [userInfo, systemStatus] = await Promise.all([
625
- api.user.getUserInfo(),
626
- api.common.getSystemStatus()
627
- ]);
628
-
629
- console.log('用户信息:', userInfo);
630
- console.log('系统状态:', systemStatus);
631
- } catch (error) {
632
- console.error('请求失败:', error);
633
- }
634
- }
635
- \`\`\`
636
-
637
- ### 6. 取消请求
638
-
639
- \`\`\`typescript
640
- import { request } from '@/api';
641
-
642
- // 创建取消令牌
643
- const CancelToken = request.axios.CancelToken;
644
- const source = CancelToken.source();
645
-
646
- // 发送请求
647
- request.get('/api/long-running', {
648
- cancelToken: source.token
649
- });
650
-
651
- // 取消请求
652
- function cancelRequest() {
653
- source.cancel('用户取消了请求');
654
- }
655
- \`\`\`
656
-
657
- ## Vue 3组件中使用示例
658
-
659
- \`\`\`vue
660
- <script setup lang="ts">
661
- import { ref, onMounted } from 'vue';
662
- import { api } from '@/api';
663
-
664
- const loading = ref(false);
665
- const userList = ref([]);
666
- const errorMsg = ref('');
667
-
668
- const fetchUsers = async (page = 1) => {
669
- loading.value = true;
670
- errorMsg.value = '';
671
-
672
- try {
673
- const result = await api.user.getUserList({ page, pageSize: 10 });
674
- userList.value = result.list;
675
- } catch (error) {
676
- errorMsg.value = error.message || '获取用户列表失败';
677
- } finally {
678
- loading.value = false;
679
- }
680
- };
681
-
682
- onMounted(() => {
683
- fetchUsers();
684
- });
685
- </script>
686
-
687
- <template>
688
- <div class="user-list">
689
- <div v-if="loading">加载中...</div>
690
- <div v-else-if="errorMsg" class="error">{{ errorMsg }}</div>
691
- <div v-else>
692
- <div v-for="user in userList" :key="user.id" class="user-item">
693
- {{ user.name }} - {{ user.email }}
694
- </div>
695
- </div>
696
- </div>
697
- </template>
698
- \`\`\`
699
-
700
- ## 扩展说明
701
-
702
- ### 1. 添加新的API模块
703
-
704
- 1. 在\`/src/api/\`目录下创建新的API文件,例如\`productApi.ts\`
705
- 2. 在文件中定义API接口和相关类型
706
- 3. 在`/ src / api / index.ts`中导入并导出新模块
707
-
708
- ### 2. 自定义配置
709
-
710
- 可以在\`axiosConfig.ts\`中修改配置:
711
- - \`API_BASE_URL\`:修改API基础URL
712
- - \`REQUEST_TIMEOUT\`:调整请求超时时间
713
- - \`errorMessageMap\`:自定义错误消息 (可选)
714
-
715
- ### 3. 全局错误处理
716
-
717
- 可以在\`errorHandler.ts\`的\`globalErrorHandler\`函数中添加:
718
- - 错误日志上报
719
- - 统一错误提示
720
- - 根据错误类型执行不同操作
721
-
722
- ## 注意事项
723
-
724
- 1. 所有API调用都应该使用\`try/catch\`进行错误处理
725
- 2. 登录成功后,token会自动保存到localStorage,并在后续请求中自动添加
726
- 3. 未授权错误(401)会自动清除token,可以在组件中监听此错误进行页面跳转
727
- 4. 文件上传时,需要使用FormData格式
728
- 5. 对于大型项目,可以根据业务模块创建更多API文件
729
-
730
- **************************************************
731
- # 工具函数库
732
-
733
- ## 图片地址处理工具
734
-
735
- ### 主要功能
736
- - 拼接图片基础URL和相对路径
737
- - 智能处理URL中的斜杠,避免重复
738
- - 识别并保留完整URL(以http或https开头的路径)
739
- - 支持批量图片URL处理
740
- - 提供Vue组件和组合式API使用方式
741
-
742
- ### 使用方法
743
-
744
- #### 1. 直接使用工具函数
745
-
746
- \`\`\`typescript
747
- import { joinImageUrl, joinImageUrls } from '@/utils/imageUtils';
748
-
749
- // 单个图片URL拼接
750
- const imageUrl = joinImageUrl('https://cdn.example.com', 'images/product.jpg');
751
- // 结果: https://cdn.example.com/images/product.jpg
752
-
753
- // 批量图片URL拼接
754
- const imageUrls = joinImageUrls([
755
- 'images/1.jpg',
756
- 'images/2.jpg'
757
- ], 'https://cdn.example.com');
758
- \`\`\`
759
-
760
- #### 2. 使用组合式API(在Vue组件中)
761
-
762
- \`\`\`typescript
763
- import { useImageUrl } from '@/utils/imageUtils';
764
-
765
- // 创建自定义基础URL的图片工具
766
- const imageTools = useImageUrl('https://cdn.example.com');
767
-
768
- // 单个图片URL
769
- const imageUrl = imageTools.getImageUrl('images/product.jpg');
770
-
771
- // 或使用自定义基础URL覆盖默认值
772
- const imageUrlWithCustomBase = imageTools.getImageUrl('images/product.jpg', 'https://custom.example.com');
773
- \`\`\`
774
-
775
- #### 3. 使用Vue组件
776
-
777
- \`\`\`vue
778
- <template>
779
- <!-- 简单使用 -->
780
- <ImageUrl path="images/product.jpg" />
781
-
782
- <!-- 使用自定义基础URL -->
783
- <ImageUrl path="images/product.jpg" base-url="https://cdn.example.com" />
784
-
785
- <!-- 使用插槽自定义渲染 -->
786
- <ImageUrl path="images/product.jpg" #default="{ url }">
787
- <img :src="url" alt="产品图片" />
788
- </ImageUrl>
789
- </template>
790
-
791
- \`\`\`
792
-
793
- ### 配置说明
794
-
795
- 可以在环境变量文件(.env)中配置默认图片基础URL:
796
-
797
- \`\`\`
798
- VITE_IMAGE_BASE_URL=https://cdn.example.com
799
- \`\`\`
800
-
801
- 如果未配置,默认值为'/'(网站根目录)。
802
-
803
- ### 注意事项
804
- - 工具会自动处理URL中的斜杠,避免重复
805
- - 如果提供的图片路径已经是完整URL,将直接返回该URL
806
- - 对于空路径,函数会返回空字符串,避免生成无效URL
807
- `
110
+ content: readTemplateFile('plugins/axios/files/README.md')
808
111
  },
809
112
  {
810
113
  path: 'src/api/index.ts',
811
- content: `
812
- // API接口管理入口文件
813
-
814
- // 导出各个模块的API
815
- import * as yApi from './app/yApi';
816
-
817
- // 统一导出所有API
818
- export {
819
- yApi,
820
- };
821
-
822
- // 导出axios实例和请求方法,便于直接使用
823
- import http, { request } from '../utils/axiosInstance';
824
- export { http, request };
825
-
826
- // 导出错误处理相关工具
827
- export * from '../utils/errorHandler';
828
-
829
- `
114
+ content: readTemplateFile('plugins/axios/files/index.ts')
830
115
  },
831
116
  ]
832
117
  }
@@ -835,7 +120,7 @@ const plugins = [
835
120
 
836
121
  // 读取配置文件
837
122
  function getConfig() {
838
- const configPath = path.join(process.cwd(), 'create-my-vue.config.js');
123
+ const configPath = path.join(process.cwd(), 'create-myvue.config.js');
839
124
  if (fs.existsSync(configPath)) {
840
125
  return require(configPath);
841
126
  }
@@ -902,7 +187,7 @@ function executeCommand(command, args, options = {}) {
902
187
  if (code === 0) {
903
188
  resolve();
904
189
  } else {
905
- reject(new Error(`Command failed with exit code ${code}`));
190
+ reject(new Error('Command failed with exit code ' + code));
906
191
  }
907
192
  });
908
193
  });
@@ -930,7 +215,7 @@ function updateProjectConfig(projectPath, selectedPlugins) {
930
215
  // 添加导入语句
931
216
  if (allImports.length > 0) {
932
217
  const importStatements = allImports.join('\n');
933
- content = content.replace(/import\s+\w+\s+from/g, match => `${importStatements}\n${match}`);
218
+ content = content.replace(/import\s+\w+\s+from/g, match => importStatements + '\n' + match);
934
219
  }
935
220
 
936
221
  // 添加插件配置
@@ -938,14 +223,9 @@ function updateProjectConfig(projectPath, selectedPlugins) {
938
223
  const pluginStatements = allPlugins.join(',\n ');
939
224
  content = content.replace(/plugins:\s*\[([\s\S]*?)\]/g, (match, existingPlugins) => {
940
225
  if (existingPlugins.trim()) {
941
- return `plugins: [
942
- ${existingPlugins.trim()},
943
- ${pluginStatements}
944
- ]`;
226
+ return 'plugins: [\n ' + existingPlugins.trim() + ',\n ' + pluginStatements + '\n ]';
945
227
  } else {
946
- return `plugins: [
947
- ${pluginStatements}
948
- ]`;
228
+ return 'plugins: [\n ' + pluginStatements + '\n ]';
949
229
  }
950
230
  });
951
231
  }
@@ -973,11 +253,11 @@ function updateProjectConfig(projectPath, selectedPlugins) {
973
253
  // 追加内容
974
254
  const existingContent = fs.readFileSync(filePath, 'utf8');
975
255
  fs.writeFileSync(filePath, existingContent + fileConfig.content, 'utf8');
976
- console.log(`成功追加到 ${fileConfig.path}`);
256
+ console.log('成功追加到 ' + fileConfig.path);
977
257
  } else {
978
258
  // 创建或覆盖文件
979
259
  fs.writeFileSync(filePath, fileConfig.content, 'utf8');
980
- console.log(`成功创建 ${fileConfig.path}`);
260
+ console.log('成功创建 ' + fileConfig.path);
981
261
  }
982
262
  });
983
263
  }
@@ -994,12 +274,12 @@ async function main(projectName, options) {
994
274
  projectName: projectName || config.projectName,
995
275
  ...config,
996
276
  ...options
997
- };
277
+ }
998
278
 
999
279
  // 构建 pnpm create vue@latest 命令
1000
280
  const args = ['create', 'vue@latest', ...parseConfigToArgs(finalConfig)];
1001
281
 
1002
- console.log(`Running: pnpm ${args.join(' ')}`);
282
+ console.log('Running: pnpm ' + args.join(' '));
1003
283
 
1004
284
  // 如果是 dry-run,只显示命令不执行
1005
285
  if (finalConfig.dryRun) {
@@ -1025,22 +305,22 @@ async function main(projectName, options) {
1025
305
 
1026
306
  if (!fs.existsSync(composablesPath)) {
1027
307
  fs.mkdirSync(composablesPath, { recursive: true });
1028
- console.log(`成功创建 ${composablesPath}`);
308
+ console.log('成功创建 ' + composablesPath);
1029
309
  }
1030
310
 
1031
311
  if (!fs.existsSync(utilsPath)) {
1032
312
  fs.mkdirSync(utilsPath, { recursive: true });
1033
- console.log(`成功创建 ${utilsPath}`);
313
+ console.log('成功创建 ' + utilsPath);
1034
314
  }
1035
315
 
1036
316
  if (!fs.existsSync(iconPath)) {
1037
317
  fs.mkdirSync(iconPath, { recursive: true });
1038
- console.log(`成功创建 ${iconPath}`);
318
+ console.log('成功创建 ' + iconPath);
1039
319
  }
1040
320
 
1041
321
  if (!fs.existsSync(apiPath)) {
1042
322
  fs.mkdirSync(apiPath, { recursive: true });
1043
- console.log(`成功创建 ${apiPath}`);
323
+ console.log('成功创建 ' + apiPath);
1044
324
  }
1045
325
 
1046
326
  const { selectedPlugins } = await inquirer.prompt([
@@ -1049,7 +329,7 @@ async function main(projectName, options) {
1049
329
  name: 'selectedPlugins',
1050
330
  message: '您想要添加哪些额外的插件?',
1051
331
  choices: plugins.map(plugin => ({
1052
- name: `${plugin.name} - ${plugin.description}`,
332
+ name: plugin.name + ' - ' + plugin.description,
1053
333
  value: plugin.name
1054
334
  }))
1055
335
  }
@@ -1079,7 +359,7 @@ async function main(projectName, options) {
1079
359
  }
1080
360
  }
1081
361
  } catch (error) {
1082
- console.error(`Error: ${error.message}`);
362
+ console.error('Error: ' + error.message);
1083
363
  process.exit(1);
1084
364
  }
1085
365
  }
@@ -1111,4 +391,4 @@ program
1111
391
  main(projectName, options);
1112
392
  });
1113
393
 
1114
- program.parse(process.argv);
394
+ program.parse(process.argv);