chanjs 1.2.6 → 2.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/common/global.js +54 -0
- package/core/controller.js +29 -0
- package/core/index.js +3 -0
- package/core/service.js +297 -0
- package/extend/art-template.js +28 -0
- package/extend/import.js +6 -0
- package/index.js +117 -163
- package/middleware/cookie.js +4 -0
- package/middleware/cors.js +4 -0
- package/middleware/favicon.js +5 -0
- package/middleware/header.js +9 -0
- package/middleware/index.js +21 -0
- package/middleware/log.js +4 -0
- package/middleware/setBody.js +11 -0
- package/middleware/static.js +10 -0
- package/middleware/template.js +14 -0
- package/middleware/validator.js +23 -0
- package/package.json +2 -3
- package/utils/bind.js +21 -0
- package/utils/db.js +75 -0
- package/utils/index.js +11 -0
- package/utils/loader.js +63 -0
- package/utils/response.js +26 -0
- package/core/config.js +0 -52
- package/core/helper.js +0 -105
- package/core/lib/cache.js +0 -133
- package/core/lib/controller.js +0 -56
- package/core/lib/index.js +0 -32
- package/core/lib/service.js +0 -269
- package/core/lib/task.js +0 -140
- package/core/lib/view.js +0 -47
package/index.js
CHANGED
@@ -1,68 +1,90 @@
|
|
1
|
-
import
|
1
|
+
import "./common/global.js";
|
2
2
|
import path from "path";
|
3
3
|
import fs from "fs";
|
4
|
-
import
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
import
|
13
|
-
|
14
|
-
import {
|
15
|
-
|
16
|
-
|
17
|
-
|
4
|
+
import {
|
5
|
+
bindClass,
|
6
|
+
db,
|
7
|
+
loaderSort,
|
8
|
+
getPackage,
|
9
|
+
loadConfig,
|
10
|
+
loadController,
|
11
|
+
} from "./utils/index.js";
|
12
|
+
import { express, z } from "./extend/import.js";
|
13
|
+
import { Controller, Service } from "./core/index.js";
|
14
|
+
import {
|
15
|
+
log,
|
16
|
+
setCookie,
|
17
|
+
setFavicon,
|
18
|
+
setBody,
|
19
|
+
setStatic,
|
20
|
+
setHeader,
|
21
|
+
setTemplate,
|
22
|
+
Cors,
|
23
|
+
validator,
|
24
|
+
} from "./middleware/index.js";
|
25
|
+
|
18
26
|
class Chan {
|
19
|
-
static helper = {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
static
|
27
|
+
static helper = {
|
28
|
+
bindClass,
|
29
|
+
getPackage,
|
30
|
+
loadController,
|
31
|
+
db,
|
32
|
+
z, //验证器
|
33
|
+
validator,
|
34
|
+
}; //工具类
|
35
|
+
static config = {}; //配置
|
36
|
+
//数据库
|
37
|
+
|
38
|
+
// static Router = express.Router; //路由
|
39
|
+
static Service = Service; //服务
|
40
|
+
static Controller = Controller; //控制器
|
41
|
+
static extend = {}; //组件扩展
|
42
|
+
static middleware = {}; //中间件
|
43
|
+
|
28
44
|
constructor() {
|
29
45
|
this.app = express();
|
30
46
|
this.router = express.Router();
|
31
47
|
}
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
this.loadCore();
|
36
|
-
this.loadDB();
|
37
|
-
this.loadCors();
|
38
|
-
}
|
39
|
-
async loadConfig() {
|
40
|
-
const configPath = path.join(Chan.config.APP_PATH, "config/index.js");
|
41
|
-
if (fs.existsSync(configPath)) {
|
42
|
-
const configUrl = pathToFileURL(configPath).href; // 新增转换
|
43
|
-
const configModule = await import(configUrl); // 使用 URL 导入
|
44
|
-
Chan.config = { ...Chan.config, ...configModule.default }; // 注意 default
|
45
|
-
}
|
48
|
+
|
49
|
+
beforeStart(cb) {
|
50
|
+
cb && cb();
|
46
51
|
}
|
47
52
|
|
48
|
-
async
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
const filePath = path.join(extendPath, file);
|
54
|
-
const fileUrl = pathToFileURL(filePath).href; // 转换路径
|
55
|
-
const helperModule = await import(fileUrl); // 使用 URL 导入
|
56
|
-
Chan.helper[file.replace(".js", "")] = helperModule?.default || helperModule; // 注意 default
|
57
|
-
}
|
58
|
-
}
|
53
|
+
async init() {
|
54
|
+
await this.config();
|
55
|
+
await this.loadExtend(); //utils
|
56
|
+
this.loadMiddleware();
|
57
|
+
this.loadDB();
|
59
58
|
}
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
//加载配置文件
|
61
|
+
async config() {
|
62
|
+
let config = await loadConfig();
|
63
|
+
Chan.config = config;
|
64
|
+
}
|
65
|
+
|
66
|
+
//加载中间件
|
67
|
+
async loadMiddleware() {
|
68
|
+
const {
|
69
|
+
views,
|
70
|
+
env,
|
71
|
+
appName,
|
72
|
+
version,
|
73
|
+
cookieKey,
|
74
|
+
JSON_LIMIT,
|
75
|
+
statics,
|
76
|
+
logger,
|
77
|
+
cors,
|
78
|
+
} = Chan.config;
|
79
|
+
|
80
|
+
log(this.app, logger);
|
81
|
+
setFavicon(this.app);
|
82
|
+
setCookie(this.app, cookieKey);
|
83
|
+
setBody(this.app, JSON_LIMIT);
|
84
|
+
setTemplate(this.app, { views, env });
|
85
|
+
setStatic(this.app, statics);
|
86
|
+
Cors(this.app, cors);
|
87
|
+
setHeader(this.app, { appName, version });
|
66
88
|
}
|
67
89
|
|
68
90
|
//数据库操作
|
@@ -70,135 +92,66 @@ class Chan {
|
|
70
92
|
if (Chan.config?.db?.length > 0) {
|
71
93
|
Chan.config.db.map((item, index) => {
|
72
94
|
if (index == 0) {
|
73
|
-
Chan.knex =
|
95
|
+
Chan.knex = db(item);
|
74
96
|
} else {
|
75
|
-
Chan[`knex${index}`] =
|
97
|
+
Chan[`knex${index}`] = db(item);
|
76
98
|
}
|
77
|
-
})
|
78
|
-
Chan.Service = Service;
|
99
|
+
});
|
79
100
|
}
|
80
101
|
}
|
81
102
|
|
82
|
-
|
83
|
-
|
84
|
-
Chan.config?.cors?.origin && this.app.use(cors(Chan.config.cors));
|
85
|
-
}
|
86
|
-
|
87
|
-
//开始启动
|
88
|
-
beforeStart(cb) {
|
89
|
-
cb && cb();
|
90
|
-
}
|
91
|
-
//启动
|
92
|
-
async start(cb) {
|
93
|
-
await this.init();
|
94
|
-
await this.loadPlugins();
|
95
|
-
await this.loadModules();
|
96
|
-
await this.loadCommonRouter();
|
97
|
-
cb && cb();
|
98
|
-
}
|
99
|
-
|
100
|
-
// 加载插件
|
101
|
-
async loadPlugins() {
|
102
|
-
await this.loadModules("plugins");
|
103
|
-
}
|
104
|
-
|
105
|
-
/**
|
106
|
-
* @description 模块加载入口(路由&控制器& 服务)
|
107
|
-
*/
|
108
|
-
async loadModules(modules = "modules") {
|
109
|
-
const configPath = path.join(Chan.config.APP_PATH, modules);
|
103
|
+
async loadRouter() {
|
104
|
+
const configPath = path.join(APP_PATH, "modules");
|
110
105
|
if (fs.existsSync(configPath)) {
|
111
|
-
const dirs =
|
112
|
-
Chan[modules] = {};
|
113
|
-
|
114
|
-
// 先加载所有服务
|
106
|
+
const dirs = loaderSort(Chan.config.modules);
|
115
107
|
for (const item of dirs) {
|
116
|
-
|
117
|
-
|
118
|
-
controller: {},
|
119
|
-
};
|
120
|
-
await this.loadServices(modules, item); // 确保每个模块的服务加载完成
|
121
|
-
}
|
122
|
-
|
123
|
-
// 加载控制器和路由
|
124
|
-
for (const item of dirs) {
|
125
|
-
await this.loadModule(modules, item); // 确保每个模块的加载完成
|
108
|
+
let router = await importRootFile(`app/modules/${item}/router.js`);
|
109
|
+
router(this.app, this.router, Chan.config);
|
126
110
|
}
|
127
111
|
}
|
128
112
|
}
|
129
113
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
114
|
+
//通用路由,加载错误处理和500路由和爬虫处理
|
115
|
+
async loadCommonRouter() {
|
116
|
+
try {
|
117
|
+
let router = await importRootFile("app/router.js");
|
118
|
+
router(this.app, this.router, Chan.config);
|
119
|
+
} catch (error) {
|
120
|
+
console.log(error);
|
121
|
+
}
|
137
122
|
}
|
138
123
|
|
139
|
-
async
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
Chan[modules][moduleName][type][name] = { ...bindClass(module.default) };
|
150
|
-
} catch (e) {
|
151
|
-
console.error(`加载${type}模块失败: ${file}`, e);
|
152
|
-
throw e;
|
153
|
-
}
|
154
|
-
}));
|
124
|
+
async loadExtend() {
|
125
|
+
if (fs.existsSync(EXTEND_PATH)) {
|
126
|
+
const files = fs
|
127
|
+
.readdirSync(EXTEND_PATH)
|
128
|
+
.filter((file) => file.endsWith(".js"));
|
129
|
+
for (const file of files) {
|
130
|
+
const filePath = path.join(EXTEND_PATH, file);
|
131
|
+
let helperModule = await importFile(filePath);
|
132
|
+
Chan.helper[file.replace(".js", "")] = helperModule;
|
133
|
+
}
|
155
134
|
}
|
156
135
|
}
|
157
136
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
*/
|
163
|
-
async loadServices(modules, moduleName) {
|
164
|
-
await this.loadFiles(modules, moduleName, "service");
|
165
|
-
}
|
137
|
+
async start(cb) {
|
138
|
+
await this.init();
|
139
|
+
await this.loadRouter();
|
140
|
+
await this.loadCommonRouter();
|
166
141
|
|
167
|
-
|
168
|
-
* @description 扫描模块下所有controller
|
169
|
-
* @param {*} moduleDir 模块路径
|
170
|
-
* @param {*} moduleName 模块名称
|
171
|
-
*/
|
172
|
-
async loadControllers(modules, moduleName) {
|
173
|
-
await this.loadFiles(modules, moduleName, "controller");
|
142
|
+
cb && cb();
|
174
143
|
}
|
175
144
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
const routeUrl = pathToFileURL(routersDir).href; // 转换路径
|
185
|
-
const routes = await import(routeUrl); // 使用 URL 导入
|
186
|
-
routes.default({ router: this.router, modules: Chan[modules], app: this.app });
|
187
|
-
}
|
188
|
-
}
|
145
|
+
getAllRouter() {
|
146
|
+
// 获取所有路径
|
147
|
+
const routes = this.router.stack
|
148
|
+
.filter((r) => r.route) // 过滤掉中间件
|
149
|
+
.map((r) => ({
|
150
|
+
path: r.route.path,
|
151
|
+
methods: Object.keys(r.route.methods),
|
152
|
+
}));
|
189
153
|
|
190
|
-
|
191
|
-
async loadCommonRouter() {
|
192
|
-
try {
|
193
|
-
const baseRouterPath = path.join(Chan.config.APP_PATH, "router.js");
|
194
|
-
if (fs.existsSync(baseRouterPath)) {
|
195
|
-
const routerUrl = pathToFileURL(baseRouterPath).href; // 转换路径
|
196
|
-
const _router = await import(routerUrl); // 使用 URL 导入
|
197
|
-
_router.default(this.app, this.router, Chan.config); // 注意 default
|
198
|
-
}
|
199
|
-
} catch (error) {
|
200
|
-
console.log(error);
|
201
|
-
}
|
154
|
+
console.log(routes);
|
202
155
|
}
|
203
156
|
|
204
157
|
run(cb) {
|
@@ -208,5 +161,6 @@ class Chan {
|
|
208
161
|
});
|
209
162
|
}
|
210
163
|
}
|
164
|
+
|
211
165
|
global.Chan = Chan;
|
212
166
|
export default Chan;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import {log} from "./log.js";
|
2
|
+
import {setCookie} from "./cookie.js";
|
3
|
+
import {setFavicon} from "./favicon.js";
|
4
|
+
import {setBody} from "./setBody.js";
|
5
|
+
import {setStatic} from "./static.js";
|
6
|
+
import {setHeader} from "./header.js";
|
7
|
+
import {setTemplate} from "./template.js";
|
8
|
+
import {validator} from "./validator.js";
|
9
|
+
import {Cors} from "./cors.js";
|
10
|
+
|
11
|
+
export {
|
12
|
+
log,
|
13
|
+
setCookie,
|
14
|
+
setFavicon,
|
15
|
+
setBody,
|
16
|
+
setStatic,
|
17
|
+
setHeader,
|
18
|
+
setTemplate,
|
19
|
+
Cors,
|
20
|
+
validator
|
21
|
+
}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import express from "express";
|
2
|
+
|
3
|
+
export const setStatic = async function (app, statics) {
|
4
|
+
if (statics.length > 0) {
|
5
|
+
statics.forEach((item) => {
|
6
|
+
const { prefix, dir, maxAge } = item;
|
7
|
+
app.use(prefix, express.static(dir, { maxAge: maxAge || 0 }));
|
8
|
+
});
|
9
|
+
}
|
10
|
+
};
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import '../extend/art-template.js'
|
2
|
+
export let setTemplate = (app, config) => {
|
3
|
+
const { views, env } = config;
|
4
|
+
//合并插件中的view
|
5
|
+
const all = [...views, 'app/modules/web/view'];
|
6
|
+
app.set("view options", {
|
7
|
+
debug: env === "dev",
|
8
|
+
cache: env === "prd",
|
9
|
+
minimize: true,
|
10
|
+
});
|
11
|
+
app.set("view engine", "html");
|
12
|
+
app.set("views", all);
|
13
|
+
app.engine(".html", requirejs("express-art-template"));
|
14
|
+
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
export const validator = (schemas) => (req, res, next) => {
|
2
|
+
// 分别验证 headers/params/query/body
|
3
|
+
const sections = {
|
4
|
+
headers: schemas.headers,
|
5
|
+
params: schemas.params,
|
6
|
+
query: schemas.query,
|
7
|
+
body: schemas.body
|
8
|
+
};
|
9
|
+
|
10
|
+
for (const [key, schema] of Object.entries(sections)) {
|
11
|
+
if (!schema) continue;
|
12
|
+
|
13
|
+
const result = schema.safeParse(req[key]);
|
14
|
+
if (!result.success) {
|
15
|
+
// 返回首个错误信息
|
16
|
+
const firstError = result.error.errors[0];
|
17
|
+
return res.status(400).json({ error: firstError.message });
|
18
|
+
}
|
19
|
+
// 将验证后的数据挂载到 req 对象
|
20
|
+
req[key] = result.data;
|
21
|
+
}
|
22
|
+
next();
|
23
|
+
};
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"type": "module",
|
3
3
|
"name": "chanjs",
|
4
|
-
"version": "
|
4
|
+
"version": "2.0.0",
|
5
5
|
"description": "chanjs基于express5 纯js研发的轻量级mvc框架。",
|
6
6
|
"main": "index.js",
|
7
7
|
"module": "index.js",
|
@@ -11,7 +11,7 @@
|
|
11
11
|
"express mysql",
|
12
12
|
"express knex",
|
13
13
|
"chancms",
|
14
|
-
"nodejs"
|
14
|
+
"nodejs mvc"
|
15
15
|
],
|
16
16
|
"engines": {
|
17
17
|
"node": ">=20.0.0"
|
@@ -24,7 +24,6 @@
|
|
24
24
|
"cookie-parser": "^1.4.7",
|
25
25
|
"cors": "^2.8.5",
|
26
26
|
"dayjs": "^1.11.13",
|
27
|
-
"deepmerge": "^4.3.1",
|
28
27
|
"express": "^5.1.0",
|
29
28
|
"express-art-template": "^1.0.1",
|
30
29
|
"knex": "^3.1.0",
|
package/utils/bind.js
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
/**
|
3
|
+
* @description 实例化一个类,并将该类的所有方法绑定到一个新的对象上。
|
4
|
+
* @param {Function} className - 需要实例化的类。
|
5
|
+
*@returns {Object} 包含绑定方法的对象。
|
6
|
+
*/
|
7
|
+
export const bindClass = function(className) {
|
8
|
+
let obj = {};
|
9
|
+
const cls = new className();
|
10
|
+
Object.getOwnPropertyNames(cls.constructor.prototype).forEach(
|
11
|
+
(methodName) => {
|
12
|
+
if (
|
13
|
+
methodName !== "constructor" &&
|
14
|
+
typeof cls[methodName] === "function"
|
15
|
+
) {
|
16
|
+
obj[methodName] = cls[methodName].bind(cls);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
);
|
20
|
+
return obj;
|
21
|
+
}
|
package/utils/db.js
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
import knex from 'knex';
|
2
|
+
export const db = function({
|
3
|
+
client='mysql2',
|
4
|
+
host='127.0.0.1',
|
5
|
+
user='root',
|
6
|
+
password='123456',
|
7
|
+
database='test',
|
8
|
+
debug=true,
|
9
|
+
charset='utf8mb4',
|
10
|
+
min=0,
|
11
|
+
max=2,
|
12
|
+
} ) {
|
13
|
+
|
14
|
+
let config = {
|
15
|
+
client ,
|
16
|
+
connection: {
|
17
|
+
host ,
|
18
|
+
user ,
|
19
|
+
password,
|
20
|
+
database,
|
21
|
+
charset,
|
22
|
+
} ,
|
23
|
+
debug,
|
24
|
+
pool: { //默认为{min: 2, max: 10},连接池配置
|
25
|
+
min,
|
26
|
+
max,
|
27
|
+
},
|
28
|
+
log: {
|
29
|
+
warn(message) {
|
30
|
+
console.error("[knex warn]", message);
|
31
|
+
},
|
32
|
+
error(message) {
|
33
|
+
console.error("[knex error]", message);
|
34
|
+
},
|
35
|
+
debug(message) {
|
36
|
+
console.log("[knex debug]", message);
|
37
|
+
},
|
38
|
+
deprecate(message) {
|
39
|
+
console.warn("[knex deprecate]", message);
|
40
|
+
},
|
41
|
+
trace(message) {
|
42
|
+
console.log("[knex trace]", message);
|
43
|
+
},
|
44
|
+
log(message) {
|
45
|
+
console.log("[knex log]", message);
|
46
|
+
},
|
47
|
+
info(message) {
|
48
|
+
console.log("[knex info]", message);
|
49
|
+
},
|
50
|
+
|
51
|
+
},
|
52
|
+
}
|
53
|
+
return knex(config);
|
54
|
+
}
|
55
|
+
|
56
|
+
const errCode = {
|
57
|
+
"ECONNREFUSED": "数据库连接被拒绝,请检查数据库服务是否正常运行。",
|
58
|
+
"ER_ACCESS_DENIED_ERROR": "无权限访问,账号或密码错误。",
|
59
|
+
"ER_ROW_IS_REFERENCED_2": "无法删除或更新记录,存在关联数据。",
|
60
|
+
"ER_BAD_FIELD_ERROR": "SQL语句中包含无效字段,请检查查询条件或列名。",
|
61
|
+
"ER_DUP_ENTRY": "插入失败:数据重复,违反唯一性约束。",
|
62
|
+
"ER_NO_SUCH_TABLE": "操作失败:目标表不存在。",
|
63
|
+
"ETIMEOUT": "数据库操作超时,请稍后再试。"
|
64
|
+
}
|
65
|
+
const getDefaultErrorMessage = (error) => {
|
66
|
+
if (error.message.includes('syntax') ||
|
67
|
+
error.message.includes('SQL')) {
|
68
|
+
return '数据库语法错误,请检查您的查询语句。';
|
69
|
+
} else if (error.message.includes('Connection closed')) {
|
70
|
+
return '数据库连接已关闭,请重试。';
|
71
|
+
} else if (error.message.includes('permission')) {
|
72
|
+
return '数据库权限不足,请检查配置。';
|
73
|
+
}
|
74
|
+
return '数据库发生未知错误,请稍后重试。';
|
75
|
+
}
|
package/utils/index.js
ADDED
package/utils/loader.js
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
import fs from 'fs';
|
2
|
+
import path from 'path';
|
3
|
+
|
4
|
+
/**
|
5
|
+
*
|
6
|
+
* @param {*} module 模块目录
|
7
|
+
* @returns Array
|
8
|
+
* @description 将web模块放到最后加载
|
9
|
+
*/
|
10
|
+
export const loaderSort = (modules=[])=>{
|
11
|
+
const index = modules.indexOf('web');
|
12
|
+
if (index !== -1) {
|
13
|
+
const web = modules.splice(index, 1);
|
14
|
+
modules.push(web[0]);
|
15
|
+
}
|
16
|
+
return modules;
|
17
|
+
}
|
18
|
+
|
19
|
+
export const getPackage = async function(){
|
20
|
+
let pkg = await importFile('package.json')
|
21
|
+
return pkg;
|
22
|
+
}
|
23
|
+
|
24
|
+
export const loadConfig = async function(){
|
25
|
+
let config = await importFile('app/config/index.js')
|
26
|
+
return config;
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
/**
|
31
|
+
* 加载指定模块名下的所有控制器文件
|
32
|
+
* @param {string} moduleName - 模块名称
|
33
|
+
* @returns {Promise<Object>} - 控制器对象
|
34
|
+
*/
|
35
|
+
export const loadController = async function (moduleName) {
|
36
|
+
const controller = {};
|
37
|
+
|
38
|
+
const dir = path.join(MODULES_PATH, moduleName,'controller');
|
39
|
+
|
40
|
+
if (!fs.existsSync(dir)) {
|
41
|
+
console.warn(`模块路径不存在,跳过加载控制器: ${dir}`);
|
42
|
+
return controller;
|
43
|
+
}
|
44
|
+
|
45
|
+
const files = fs.readdirSync(dir).filter(file => file.endsWith('.js'));
|
46
|
+
for (const file of files) {
|
47
|
+
const filePath = path.join(dir, file);
|
48
|
+
const name = file.replace(/\.js$/i, ''); // 安全处理 .js 后缀
|
49
|
+
try {
|
50
|
+
const module = await importFile(filePath);
|
51
|
+
controller[name] = { ...module};
|
52
|
+
} catch (e) {
|
53
|
+
console.error(`加载控制器失败: ${filePath}`, e);
|
54
|
+
// 可选:抛出错误或继续加载其他文件
|
55
|
+
// throw e;
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
return controller;
|
60
|
+
};
|
61
|
+
|
62
|
+
|
63
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
export let success = (data) => {
|
2
|
+
return {
|
3
|
+
success: true,
|
4
|
+
msg: "操作成功",
|
5
|
+
code: 200,
|
6
|
+
data,
|
7
|
+
};
|
8
|
+
};
|
9
|
+
|
10
|
+
export let fail = (data, code = 201) => {
|
11
|
+
return {
|
12
|
+
success: false,
|
13
|
+
msg: "操作失败",
|
14
|
+
code,
|
15
|
+
data,
|
16
|
+
};
|
17
|
+
};
|
18
|
+
|
19
|
+
export let err = (data = {}, code = 500) => {
|
20
|
+
return {
|
21
|
+
success: false,
|
22
|
+
msg: "系统异常",
|
23
|
+
code,
|
24
|
+
data,
|
25
|
+
};
|
26
|
+
};
|