create-pixle-koa-template 1.0.0 → 1.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-pixle-koa-template",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Koa template",
5
5
  "bin": {
6
6
  "create-pixle-koa-template": "./bin/create-app.js"
@@ -12,6 +12,10 @@
12
12
  "engines": {
13
13
  "node": ">=18.0.0"
14
14
  },
15
- "keywords": ["koa", "template", "pixle" ],
15
+ "keywords": [
16
+ "koa",
17
+ "template",
18
+ "pixle"
19
+ ],
16
20
  "license": "MIT"
17
- }
21
+ }
package/template/.env CHANGED
@@ -9,9 +9,9 @@ JWT_SECRET=your_jwt_secret_key_here # 密钥
9
9
  # 邮箱配置
10
10
  EMAIL_HOST=smtp.qq.com # QQ邮箱SMTP服务器地址
11
11
  EMAIL_PORT=465 # SSL加密端口(推荐)
12
- EMAIL_USER=your_email@example.com # 发件人邮箱地址
13
- EMAIL_PASS=your_email_authorization_code # 邮箱授权码(非登录密码)
14
- EMAIL_FROM=your_email@example.com # 显示的发件人地址
12
+ EMAIL_USER=your_email@example.com # 发件人邮箱地址 (改为自己的)
13
+ EMAIL_PASS=your_email_authorization_code # 邮箱授权码(非登录密码)(改为自己的)
14
+ EMAIL_FROM=your_email@example.com # 显示的发件人地址 (改为自己的)
15
15
 
16
16
 
17
17
  # 验证码配置
package/template/app.js CHANGED
@@ -26,6 +26,7 @@ app.on("error", (err, ctx) => {
26
26
 
27
27
  //添加静态资源,前缀/static,静态资源目录为public
28
28
  app.use(mount("/static", static(path.join(__dirname, "public"))));
29
+ app.use(mount("/storage/uploads/image", static(path.join(__dirname, "storage/uploads/image"))));
29
30
  // 使用 bodyParser 中间件
30
31
  app.use(bodyParser());
31
32
 
@@ -13,7 +13,7 @@ let config = {
13
13
  expiresIn: 24 * 60 * 60 * 7, // Token 有效期7天
14
14
  //不需要鉴权路由白名单
15
15
  pathWhiteList: [
16
- /^\/static\/.*/, //静态资源
16
+ // /^\/static\/.*/, //静态资源
17
17
  '/api/auth/login', //登录接口
18
18
  '/api/auth/register', //注册接口
19
19
  '/api/auth/verify-code',//发送验证码
@@ -1,6 +1,7 @@
1
1
  const koajwt = require("koa-jwt");
2
2
  const config = require("../config");
3
3
  const { getToken } = require("../services/TokenRedisService.js");
4
+ // const {verifyToken,decodeToken}=require("../services/JwtTokenService.js")
4
5
 
5
6
  /**
6
7
  * JWT 认证中间件(token校验)
@@ -1,5 +1,5 @@
1
- const path = require('path');
2
- const fs = require('fs');
1
+ const path = require("path");
2
+ const fs = require("fs");
3
3
 
4
4
  /**
5
5
  * 404 405中间件
@@ -7,78 +7,88 @@ const fs = require('fs');
7
7
  */
8
8
 
9
9
  const notFoundMiddleware = async (ctx, next) => {
10
+ // 先执行所有其他中间件
11
+ await next();
10
12
 
11
- // 先执行所有其他中间件
12
- await next();
13
+ // 如果已经有响应体,直接返回
14
+ if (ctx.body) {
15
+ return;
16
+ }
13
17
 
14
- // 如果已经有响应体,直接返回
15
- if (ctx.body) {
16
- return;
17
- }
18
-
19
- // 检查是否为405错误:路径存在但请求方法不允许
20
- let isMethodNotAllowed = false;
21
- let allowedMethods = [];
22
- let pathExists = false;
18
+ // 检查是否为405错误:路径存在但请求方法不允许
19
+ let isMethodNotAllowed = false;
20
+ let allowedMethods = [];
21
+ let pathExists = false;
23
22
 
24
- if (ctx.app.context.registeredRoutes) {
25
- const requestedPath = ctx.path;
26
- const requestedMethod = ctx.method;
23
+ if (ctx.app.context.registeredRoutes) {
24
+ const requestedPath = ctx.path;
25
+ const requestedMethod = ctx.method;
27
26
 
28
- // 遍历所有注册的路由
29
- for (const route of ctx.app.context.registeredRoutes) {
30
- // 检查路径是否匹配
31
- if (route.regexp && route.regexp.test(requestedPath)) {
32
- pathExists = true;
27
+ // 遍历所有注册的路由
28
+ for (const route of ctx.app.context.registeredRoutes) {
29
+ // 检查路径是否匹配
30
+ if (route.regexp && route.regexp.test(requestedPath)) {
31
+ pathExists = true;
33
32
 
34
- // 如果路径匹配但方法不允许,收集允许的方法
35
- if (!route.methods.includes(requestedMethod) && !route.methods.includes('HEAD')) {
36
- // 收集允许的方法(过滤掉HEAD方法,因为它通常是自动支持的)
37
- allowedMethods = [...new Set([...allowedMethods, ...route.methods.filter(m => m !== 'HEAD')])];
38
- } else {
39
- // 如果请求方法是允许的,则不是405错误
40
- isMethodNotAllowed = false;
41
- break;
42
- }
43
- }
33
+ // 如果路径匹配但方法不允许,收集允许的方法
34
+ if (
35
+ !route.methods.includes(requestedMethod) &&
36
+ !route.methods.includes("HEAD")
37
+ ) {
38
+ // 收集允许的方法(过滤掉HEAD方法,因为它通常是自动支持的)
39
+ allowedMethods = [
40
+ ...new Set([
41
+ ...allowedMethods,
42
+ ...route.methods.filter((m) => m !== "HEAD"),
43
+ ]),
44
+ ];
45
+ } else {
46
+ // 如果请求方法是允许的,则不是405错误
47
+ isMethodNotAllowed = false;
48
+ break;
44
49
  }
45
-
46
- // 只有当路径存在且允许的方法不为空时,才是405错误
47
- isMethodNotAllowed = pathExists && allowedMethods.length > 0;
50
+ }
48
51
  }
49
52
 
53
+ // 只有当路径存在且允许的方法不为空时,才是405错误
54
+ isMethodNotAllowed = pathExists && allowedMethods.length > 0;
55
+ }
50
56
 
51
- // 处理405错误
52
- if (isMethodNotAllowed) {
53
- ctx.status = 405;
54
- ctx.set('Allow', allowedMethods.join(', '));
55
- ctx.type = 'application/json';
56
- ctx.body = {
57
- code: 405,
58
- message: '请求方法不允许'
59
- };
60
- }
61
- // 处理404错误
62
- else {
63
- // 无论当前状态码是什么,对于不存在的路径都设置为404
64
- ctx.status = 404;
57
+ // 处理405错误
58
+ if (isMethodNotAllowed) {
59
+ ctx.status = 405;
60
+ ctx.set("Allow", allowedMethods.join(", "));
61
+ ctx.type = "application/json";
62
+ ctx.body = {
63
+ code: 405,
64
+ message: "请求方法不允许",
65
+ };
66
+ }
67
+ // 处理404错误
68
+ else {
69
+ // 无论当前状态码是什么,对于不存在的路径都设置为404
70
+ ctx.status = 404;
65
71
 
66
- // 检查是否为静态资源请求
67
- const isStaticResource = ctx.path.startsWith('/static/') ||
68
- /\.(jpg|jpeg|png|gif|svg|css|js|html|ico|woff|woff2|ttf|eot)$/i.test(ctx.path);
69
-
70
- if (isStaticResource) {
71
- ctx.type = 'text/html';
72
- ctx.body = fs.readFileSync(path.join(__dirname, '../public/404.html'), 'utf8');
73
- } else {
74
- ctx.type = 'application/json';
75
- ctx.body = {
76
- code: 404,
77
- message: 'request not find'
78
- };
79
- }
72
+ // 检查是否为静态资源请求
73
+ const isStaticResource =
74
+ ctx.path.startsWith("/static/") ||
75
+ /\.(jpg|jpeg|png|gif|svg|css|js|html|ico|woff|woff2|ttf|eot)$/i.test(
76
+ ctx.path
77
+ );
78
+ if (isStaticResource) {
79
+ ctx.type = "text/html";
80
+ ctx.body = fs.readFileSync(
81
+ path.join(__dirname, "../public/404.html"),
82
+ "utf8"
83
+ );
84
+ } else {
85
+ ctx.type = "application/json";
86
+ ctx.body = {
87
+ code: 404,
88
+ message: "request not find",
89
+ };
80
90
  }
81
-
91
+ }
82
92
  };
83
93
 
84
- module.exports = notFoundMiddleware;
94
+ module.exports = notFoundMiddleware;
@@ -2,9 +2,9 @@ const multer = require("@koa/multer");
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
4
  const dayjs = require("dayjs");
5
- const {upload:uploadConfig}=require('../config/index')
5
+ const { upload: uploadConfig } = require('../config/index')
6
6
  // 上传配置
7
- const {uploadDir,maxSize,maxCount} = uploadConfig
7
+ const { uploadDir, maxSize, maxCount } = uploadConfig
8
8
 
9
9
 
10
10
  // 递归创建存储目录
@@ -38,9 +38,9 @@ const uploadMiddleware = ({
38
38
  destination: (req, file, cb) => {
39
39
  // 通过 MIME 类型检测是图片类型还是其他文件
40
40
  const targetDir =
41
- uploadPath || file.mimetype.startsWith("image/")
41
+ uploadPath || (file.mimetype.startsWith("image/")
42
42
  ? uploadDir.image
43
- : uploadDir.file;
43
+ : uploadDir.file);
44
44
  //上传目录
45
45
  let realUploadDir = path.join(
46
46
  targetDir,
@@ -53,7 +53,7 @@ const uploadMiddleware = ({
53
53
  },
54
54
  filename: (req, file, cb) => {
55
55
  //文件名前缀
56
- let prefix=file.mimetype.startsWith("image/") ? "image" : "file";
56
+ let prefix = file.mimetype.startsWith("image/") ? "image" : "file";
57
57
  // 生成唯一文件名
58
58
  const fileExt = path.extname(file.originalname);
59
59
  //格式:image或file+ 时间戳 + 随机数 + 文件扩展名
@@ -67,30 +67,30 @@ const uploadMiddleware = ({
67
67
  // 自定义文件过滤器
68
68
  const _fileFilter = (req, file, cb) => {
69
69
  // 如果传入了自定义过滤器,使用自定义的
70
- if (fileFilter) {
71
- return fileFilter(req, file, cb);
72
- }
73
-
74
- // 如果指定了允许的 MIME 类型
75
- if (Array.isArray(allowedMimes) && allowedMimes.length > 0) {
76
- if (allowedMimes.includes(file.mimetype)) {
77
- cb(null, true);
78
- } else {
79
- // 生成友好的错误信息
80
- const allowedTypes = allowedMimes.map(item => {
81
- const parts = item.split('/');
82
- return parts.length > 1 ? parts[1] : parts[0];
83
- });
84
-
85
- cb(
86
- new Error(`仅支持 ${allowedTypes.join('、')} 格式的文件`),
87
- false
88
- );
89
- }
90
- } else {
91
- // 没有限制,允许所有文件
70
+ if (fileFilter) {
71
+ return fileFilter(req, file, cb);
72
+ }
73
+
74
+ // 如果指定了允许的 MIME 类型
75
+ if (Array.isArray(allowedMimes) && allowedMimes.length > 0) {
76
+ if (allowedMimes.includes(file.mimetype)) {
92
77
  cb(null, true);
78
+ } else {
79
+ // 生成友好的错误信息
80
+ const allowedTypes = allowedMimes.map(item => {
81
+ const parts = item.split('/');
82
+ return parts.length > 1 ? parts[1] : parts[0];
83
+ });
84
+
85
+ cb(
86
+ new Error(`仅支持 ${allowedTypes.join('、')} 格式的文件`),
87
+ false
88
+ );
93
89
  }
90
+ } else {
91
+ // 没有限制,允许所有文件
92
+ cb(null, true);
93
+ }
94
94
  };
95
95
 
96
96
  // 创建 multer 实例
@@ -408,7 +408,7 @@ class BaseDAO {
408
408
  };
409
409
  }
410
410
  /**
411
- * 高级搜索方法(新增)
411
+ * 高级搜索
412
412
  */
413
413
  async advancedSearch(searchConfig = {}) {
414
414
  const {