chanjs 1.1.5 → 1.1.7
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/core/helper.js +27 -0
- package/core/lib/cache.js +1 -2
- package/core/lib/service.js +127 -127
- package/core/lib/task.js +140 -0
- package/core/lib/view.js +4 -4
- package/index.js +33 -39
- package/package.json +1 -1
package/core/helper.js
CHANGED
@@ -71,3 +71,30 @@ export const loadWebToEnd = function(module=[]){
|
|
71
71
|
}
|
72
72
|
return module;
|
73
73
|
}
|
74
|
+
|
75
|
+
|
76
|
+
// import { z } from "zod";
|
77
|
+
|
78
|
+
export const zodValidator = (schemas) => (req, res, next) => {
|
79
|
+
// 分别验证 headers/params/query/body
|
80
|
+
const sections = {
|
81
|
+
headers: schemas.headers,
|
82
|
+
params: schemas.params,
|
83
|
+
query: schemas.query,
|
84
|
+
body: schemas.body
|
85
|
+
};
|
86
|
+
|
87
|
+
for (const [key, schema] of Object.entries(sections)) {
|
88
|
+
if (!schema) continue;
|
89
|
+
|
90
|
+
const result = schema.safeParse(req[key]);
|
91
|
+
if (!result.success) {
|
92
|
+
// 返回首个错误信息
|
93
|
+
const firstError = result.error.errors[0];
|
94
|
+
return res.status(400).json({ error: firstError.message });
|
95
|
+
}
|
96
|
+
// 将验证后的数据挂载到 req 对象
|
97
|
+
req[key] = result.data;
|
98
|
+
}
|
99
|
+
next();
|
100
|
+
};
|
package/core/lib/cache.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class Cache {
|
1
|
+
export default class Cache {
|
2
2
|
constructor(maxSize = 1000) {
|
3
3
|
this.cache = new Map(); // 使用 Map 存储缓存数据
|
4
4
|
this.maxSize = maxSize; // 缓存最大容量
|
@@ -104,7 +104,6 @@ class Cache {
|
|
104
104
|
}
|
105
105
|
}
|
106
106
|
|
107
|
-
export default new Cache();
|
108
107
|
|
109
108
|
// // 示例用法
|
110
109
|
// const cache = new SimpleCache(100); // 设置缓存最大容量为 100
|
package/core/lib/service.js
CHANGED
@@ -3,7 +3,7 @@ class BaseService {
|
|
3
3
|
* @description 构造函数
|
4
4
|
* @param {*} knex - knex实例
|
5
5
|
*/
|
6
|
-
constructor(DB=Chan.knex) {
|
6
|
+
constructor(DB = Chan.knex) {
|
7
7
|
this.knex = DB;
|
8
8
|
this.DB = DB;
|
9
9
|
this.model = ''; // 默认为空字符串
|
@@ -14,187 +14,187 @@ class BaseService {
|
|
14
14
|
* @param {Object} query - 包含查询参数的对象
|
15
15
|
* @returns {Promise} 返回所有记录
|
16
16
|
*/
|
17
|
-
all(query={}) {
|
18
|
-
if(Object.keys(query).length === 0) {
|
17
|
+
all(query = {}) {
|
18
|
+
if (Object.keys(query).length === 0) {
|
19
19
|
return this.DB(this.model).select();
|
20
20
|
}
|
21
21
|
return this.DB(this.model).where(query).select();
|
22
22
|
}
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
async findById({ query, field = [], len = 1 }) {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
24
|
+
/**
|
25
|
+
* @description 根据指定条件查询记录
|
26
|
+
* @param {Object} options - 包含查询参数的对象
|
27
|
+
* @param {string} options.id - 查询字段名,默认为 'id'
|
28
|
+
* @param {*} options.value - 查询字段值,默认为 0
|
29
|
+
* @param {Array} options.field - 需要返回的字段数组,默认为空(即选择所有字段)
|
30
|
+
* @param {number} options.len - 期望获取的记录数量,默认为 1(如果为 1 则使用 `.first()`,否则使用 `.limit(len)`)
|
31
|
+
* @returns {Promise} 返回匹配条件的记录或记录列表
|
32
|
+
*/
|
33
|
+
async findById({ query, field = [], len = 1 }) {
|
34
|
+
let dataQuery = this.DB(this.model).where(query);
|
35
|
+
|
36
|
+
// 字段筛选
|
37
|
+
if (field.length > 0) {
|
38
|
+
dataQuery = dataQuery.select(field);
|
39
|
+
}
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
41
|
+
// 根据len决定是获取单条记录还是多条记录
|
42
|
+
if (len === 1) {
|
43
|
+
dataQuery = dataQuery.first();
|
44
|
+
} else if (len > 1) {
|
45
|
+
dataQuery = dataQuery.limit(len);
|
46
|
+
}
|
47
|
+
let res = await dataQuery;
|
48
|
+
//返回结果 undefined 则返回空数组或空对象
|
49
|
+
return res || (len === 1 ? {} : []);
|
46
50
|
}
|
47
|
-
let res = await dataQuery;
|
48
|
-
//返回结果 undefined 则返回空数组或空对象
|
49
|
-
return res || (len === 1 ? {} : []);
|
50
|
-
}
|
51
51
|
|
52
52
|
|
53
|
-
/**
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
async insert(data = {}) {
|
59
|
-
|
60
|
-
|
53
|
+
/**
|
54
|
+
* @description 创建新记录
|
55
|
+
* @param {Object} data - 包含要插入的数据对象
|
56
|
+
* @returns {Promise<boolean>} 返回操作是否成功
|
57
|
+
*/
|
58
|
+
async insert(data = {}) {
|
59
|
+
if (Object.keys(data).length === 0) {
|
60
|
+
return false;
|
61
|
+
}
|
62
|
+
const result = await this.DB(this.model).insert(data);
|
63
|
+
return result?.length > 0 || !!result;
|
61
64
|
}
|
62
|
-
const result = await this.DB(this.model).insert(data);
|
63
|
-
return result?.length > 0 || !!result;
|
64
|
-
}
|
65
65
|
|
66
66
|
/**
|
67
67
|
* @description 插入多条记录
|
68
68
|
* @param {Array} records - 包含要插入的数据对象数组 [{<key>:<value>}, {<key>:<value>}, ...]
|
69
69
|
* @returns {Promise<Array|Number>} 返回插入后的记录或受影响行数,具体取决于数据库驱动
|
70
70
|
*/
|
71
|
-
async insertMany(records=[]) {
|
71
|
+
async insertMany(records = []) {
|
72
72
|
// 如果没有提供数据或者数据为空,则直接返回 false 或者抛出异常
|
73
73
|
if (records.length === 0) {
|
74
74
|
console.log('插入数据不能为空')
|
75
75
|
return false;
|
76
76
|
}
|
77
|
-
|
77
|
+
|
78
78
|
// 执行插入操作并获取结果
|
79
79
|
const result = await this.DB(this.model).insert(records);
|
80
|
-
|
80
|
+
|
81
81
|
// 返回插入的结果
|
82
82
|
return result;
|
83
83
|
}
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
84
|
+
|
85
|
+
/**
|
86
|
+
* @description 根据指定条件删除记录
|
87
|
+
* @param {Object} query - 包含查询条件的对象
|
88
|
+
* @returns {Promise<boolean>} 返回操作是否成功(即是否有任何记录被删除)
|
89
|
+
*/
|
90
|
+
async delete(query = {}) {
|
91
|
+
if (Object.keys(query).length === 0) {
|
92
|
+
return false;
|
93
|
+
}
|
94
|
+
const affectedRows = await this.DB(this.model).where(query).del();
|
95
|
+
return affectedRows > 0;
|
93
96
|
}
|
94
|
-
|
95
|
-
|
96
|
-
}
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
* @returns {Promise<boolean>} 返回操作是否成功
|
102
|
-
*/
|
103
|
-
async update({query, params} = {}) {
|
97
|
+
/**
|
98
|
+
* @description 根据指定条件更新记录
|
99
|
+
* @param {Object} query - 查询条件
|
100
|
+
* @param {number} params - 保存内容
|
101
|
+
* @returns {Promise<boolean>} 返回操作是否成功
|
102
|
+
*/
|
103
|
+
async update({ query, params } = {}) {
|
104
104
|
const result = await this.DB(this.model).where(query).update(params);
|
105
105
|
return { affectedRows: result };
|
106
|
-
}
|
106
|
+
}
|
107
107
|
|
108
108
|
|
109
|
-
/**
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
async updateMany(updates = []) {
|
115
|
-
|
116
|
-
|
109
|
+
/**
|
110
|
+
* @description 批量更新多条记录(基于事务保证原子性)
|
111
|
+
* @param {Array<{query: Object, params: Object}>} updates - 更新操作数组,每个元素包含查询条件和更新内容
|
112
|
+
* @returns {Promise<{ affectedRows: number[] }>} 返回每个操作影响的行数数组
|
113
|
+
*/
|
114
|
+
async updateMany(updates = []) {
|
115
|
+
// 参数合法性校验
|
116
|
+
if (!Array.isArray(updates)) {
|
117
117
|
throw new Error('参数必须为数组格式');
|
118
|
-
|
118
|
+
}
|
119
|
+
|
120
|
+
// 获取事务对象
|
121
|
+
const trx = await this.DB.transaction();
|
119
122
|
|
120
|
-
|
121
|
-
const trx = await this.DB.transaction();
|
122
|
-
|
123
|
-
try {
|
123
|
+
try {
|
124
124
|
const affectedRows = [];
|
125
125
|
// 循环处理每个更新操作
|
126
126
|
for (const { query, params } of updates) {
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
// 执行单个更新操作,使用事务对象替换原有knex实例
|
128
|
+
const result = await trx(this.model)
|
129
|
+
.where(query)
|
130
|
+
.update(params);
|
131
|
+
affectedRows.push(result);
|
132
132
|
}
|
133
133
|
// 提交事务
|
134
134
|
await trx.commit();
|
135
135
|
// 返回影响行数数组(与入参顺序一致)
|
136
136
|
return { affectedRows };
|
137
|
-
|
137
|
+
} catch (err) {
|
138
138
|
// 回滚事务
|
139
139
|
await trx.rollback();
|
140
140
|
// 错误向上抛出,由调用者处理
|
141
141
|
throw err;
|
142
|
+
}
|
142
143
|
}
|
143
|
-
}
|
144
144
|
|
145
145
|
|
146
146
|
|
147
147
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
148
|
+
/**
|
149
|
+
* 查找所有符合条件的记录,并提供分页信息。
|
150
|
+
* @param {Object} options - 包含查询参数的对象
|
151
|
+
* @param {number} options.current - 当前页码,默认第一页
|
152
|
+
* @param {number} options.pageSize - 每页大小,默认10条记录
|
153
|
+
* @param {Object} options.query - 查询条件
|
154
|
+
* @param {Array} options.field - 需要返回的字段
|
155
|
+
* @returns {Promise<Object>} 返回包含数据列表、总记录数、当前页、每页大小的对象
|
156
|
+
*/
|
157
|
+
async query({ current = 1, pageSize = 10, query = {}, field = [] }) {
|
158
|
+
const offset = (current - 1) * pageSize;
|
159
|
+
let countQuery = this.DB(this.model).count("* as total");
|
160
|
+
let dataQuery = this.DB(this.model);
|
161
|
+
// 应用查询条件
|
162
|
+
if (Object.keys(query).length > 0) {
|
163
|
+
Object.entries(query).forEach(([key, value]) => {
|
164
|
+
dataQuery = dataQuery.where(key, value);
|
165
|
+
countQuery = countQuery.where(key, value);
|
166
|
+
})
|
167
|
+
}
|
168
168
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
169
|
+
//字段筛选
|
170
|
+
if (field.length > 0) {
|
171
|
+
dataQuery = dataQuery.select(field);
|
172
|
+
}
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
174
|
+
//并行执行获取总记录数和分页数据的查询
|
175
|
+
const [totalResult, list] = await Promise.all([countQuery.first(), dataQuery.offset(offset).limit(pageSize)]);
|
176
|
+
// 提取总记录数
|
177
|
+
const total = totalResult?.total || 0;
|
178
178
|
|
179
|
-
|
180
|
-
}
|
179
|
+
return { list, total, current, pageSize };
|
180
|
+
}
|
181
181
|
|
182
182
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
async count(query=[]) {
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
183
|
+
/**
|
184
|
+
* @description 查询指定条件的记录数量
|
185
|
+
* @param {Array} query - 数组形式的多个条件 [{<key>:<value>}, {<key>:<value>}, ...]
|
186
|
+
* @returns {Promise<number>} 返回符合条件的记录数量
|
187
|
+
*/
|
188
|
+
async count(query = []) {
|
189
|
+
let dataQuery = this.DB(this.model);
|
190
|
+
if (query.length > 0) {
|
191
|
+
query.forEach((condition) => {
|
192
|
+
dataQuery = dataQuery.where(condition);
|
193
|
+
});
|
194
|
+
}
|
195
|
+
const result = await dataQuery.count("* as total").first();
|
196
|
+
return result.total || 0;
|
197
197
|
}
|
198
|
-
|
198
|
+
|
199
199
|
}
|
200
200
|
export default BaseService;
|
package/core/lib/task.js
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
const schedule = require('node-schedule');
|
2
|
+
|
3
|
+
export default class Task {
|
4
|
+
constructor(config = {}) {
|
5
|
+
this.tasks = new Map();
|
6
|
+
this.config = {
|
7
|
+
taskPrefix: 'TASK_',
|
8
|
+
maxRetry: 3,
|
9
|
+
onError: (id, err) => console.error(`[${id}] Error: ${err.message}`),
|
10
|
+
...config
|
11
|
+
};
|
12
|
+
}
|
13
|
+
|
14
|
+
/**
|
15
|
+
* 添加定时任务
|
16
|
+
* @param {string|Date|Object} rule - 调度规则(Cron/Date/RecurrenceRule)
|
17
|
+
* @param {Function} callback - 任务回调函数
|
18
|
+
* @param {boolean} [immediate=false] - 是否立即执行首次
|
19
|
+
* @returns {string} 任务ID
|
20
|
+
*/
|
21
|
+
addTask(rule, callback, immediate = false) {
|
22
|
+
const taskId = `${this.config.taskPrefix}${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
23
|
+
|
24
|
+
// 创建任务[2,7](@ref)
|
25
|
+
const job = schedule.scheduleJob(taskId, rule, async () => {
|
26
|
+
try {
|
27
|
+
await callback(taskId);
|
28
|
+
job.emit('success');
|
29
|
+
} catch (error) {
|
30
|
+
job.emit('error', error);
|
31
|
+
}
|
32
|
+
});
|
33
|
+
|
34
|
+
// 事件监听[5](@ref)
|
35
|
+
job
|
36
|
+
.on('scheduled', () => console.log(`[${taskId}] 任务已计划`))
|
37
|
+
.on('run', () => console.log(`[${taskId}] 任务执行中`))
|
38
|
+
.on('success', () => console.log(`[${taskId}] 执行成功`))
|
39
|
+
.on('error', (err) => this.config.onError(taskId, err))
|
40
|
+
.on('canceled', () => console.log(`[${taskId}] 已取消`));
|
41
|
+
|
42
|
+
this.tasks.set(taskId, job);
|
43
|
+
|
44
|
+
// 立即执行首次[3](@ref)
|
45
|
+
if (immediate) {
|
46
|
+
process.nextTick(() => callback(taskId));
|
47
|
+
}
|
48
|
+
|
49
|
+
return taskId;
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* 创建循环规则任务(简化版)
|
54
|
+
* @param {Object} options - 循环规则配置 { hour, minute, dayOfWeek 等 }
|
55
|
+
* @param {Function} callback - 任务回调
|
56
|
+
* @param {boolean} [immediate] - 是否立即执行
|
57
|
+
*/
|
58
|
+
addRecurringTask(options, callback, immediate) {
|
59
|
+
const rule = new schedule.RecurrenceRule();
|
60
|
+
Object.assign(rule, options);
|
61
|
+
return this.addTask(rule, callback, immediate);
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* 取消任务
|
66
|
+
* @param {string} taskId - 任务ID
|
67
|
+
* @param {boolean} [graceful=true] - 是否等待当前执行完成
|
68
|
+
* @returns {boolean} 是否取消成功
|
69
|
+
*/
|
70
|
+
cancelTask(taskId, graceful = true) {
|
71
|
+
const job = this.tasks.get(taskId);
|
72
|
+
if (!job) return false;
|
73
|
+
|
74
|
+
graceful ? job.cancel() : job.cancelNext();
|
75
|
+
this.tasks.delete(taskId);
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* 取消所有任务[4](@ref)
|
81
|
+
*/
|
82
|
+
cancelAllTasks() {
|
83
|
+
this.tasks.forEach(job => job.cancel());
|
84
|
+
this.tasks.clear();
|
85
|
+
schedule.gracefulShutdown();
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* 获取任务状态
|
90
|
+
* @param {string} taskId - 任务ID
|
91
|
+
* @returns {'pending'|'running'|'canceled'} 任务状态
|
92
|
+
*/
|
93
|
+
getTaskStatus(taskId) {
|
94
|
+
const job = this.tasks.get(taskId);
|
95
|
+
if (!job) return 'canceled';
|
96
|
+
return job.pendingInvocations.length > 0 ? 'pending' : 'running';
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* 获取所有任务ID
|
101
|
+
* @returns {string[]} 任务ID列表
|
102
|
+
*/
|
103
|
+
getAllTaskIds() {
|
104
|
+
return Array.from(this.tasks.keys());
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
// ==================== 使用示例 ====================
|
109
|
+
// const scheduler = new TaskScheduler({
|
110
|
+
// onError: (id, err) => console.error(`[ALERT] 任务 ${id} 失败: ${err.message}`)
|
111
|
+
// });
|
112
|
+
|
113
|
+
// // 示例1: Cron表达式任务(每分钟30秒时执行)[2](@ref)
|
114
|
+
// const task1 = scheduler.addTask('30 * * * * *', (id) => {
|
115
|
+
// console.log(`[${id}] 执行时间: ${new Date().toISOString()}`);
|
116
|
+
// });
|
117
|
+
|
118
|
+
// // 示例2: 对象语法任务(每天9:30执行)[3](@ref)
|
119
|
+
// const task2 = scheduler.addRecurringTask(
|
120
|
+
// { hour: 9, minute: 30 },
|
121
|
+
// (id) => console.log(`[${id}] 晨间任务执行`)
|
122
|
+
// );
|
123
|
+
|
124
|
+
// // 示例3: 每月1号执行(月初任务)[6](@ref)
|
125
|
+
// const task3 = scheduler.addTask('0 0 1 * *', (id) => {
|
126
|
+
// console.log(`[${id}] 月初自动报表生成`);
|
127
|
+
// });
|
128
|
+
|
129
|
+
// // 示例4: 5秒后执行的一次性任务
|
130
|
+
// const task4 = scheduler.addTask(
|
131
|
+
// new Date(Date.now() + 5000),
|
132
|
+
// (id) => console.log(`[${id}] 一次性任务完成`),
|
133
|
+
// true // 立即先执行一次
|
134
|
+
// );
|
135
|
+
|
136
|
+
// // 取消任务示例
|
137
|
+
// setTimeout(() => {
|
138
|
+
// scheduler.cancelTask(task1);
|
139
|
+
// console.log('当前活跃任务:', scheduler.getAllTaskIds());
|
140
|
+
// }, 10000);
|
package/core/lib/view.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import path from "path";
|
2
|
-
import dayjs from
|
3
|
-
import { createRequire } from
|
2
|
+
import dayjs from "dayjs";
|
3
|
+
import { createRequire } from "module";
|
4
4
|
const require = createRequire(import.meta.url);
|
5
5
|
|
6
6
|
const template = require("art-template");
|
@@ -24,8 +24,8 @@ template.defaults.imports.dateFormat = function (date, format) {
|
|
24
24
|
|
25
25
|
export default (app, config) => {
|
26
26
|
const { APP_PATH, views, env } = config;
|
27
|
-
|
28
|
-
const all = [...views,
|
27
|
+
//合并插件中的view
|
28
|
+
const all = [...views, "app/modules/web/view"];
|
29
29
|
|
30
30
|
app.set("view options", {
|
31
31
|
debug: env === "dev",
|
package/index.js
CHANGED
@@ -4,30 +4,26 @@ import fs from "fs";
|
|
4
4
|
import cors from "cors";
|
5
5
|
import { pathToFileURL } from 'url'; // 新增顶部导入
|
6
6
|
import config from "./core/config.js";
|
7
|
-
import
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
import * as helper from "./core/helper.js";
|
11
8
|
import Service from "./core/lib/service.js";
|
12
|
-
import
|
9
|
+
import Cache from './core/lib/cache.js';
|
10
|
+
import Task from "./core/lib/task.js";
|
13
11
|
import core from "./core/lib/index.js";
|
14
|
-
|
12
|
+
const {bindClass, createKnex, loadWebToEnd} = helper;
|
15
13
|
/**
|
16
14
|
* @description 基于express封装的mvc框架,遵循约定优于配置原则
|
17
15
|
*/
|
18
16
|
class Chan {
|
19
|
-
static helper =
|
17
|
+
static helper = helper;
|
20
18
|
static modules = {};
|
21
19
|
static plugins = {};
|
22
20
|
static config = config;
|
23
|
-
static
|
24
|
-
|
25
|
-
|
21
|
+
static Cache = Cache;
|
22
|
+
static Task = Task;
|
26
23
|
constructor() {
|
27
24
|
this.app = express();
|
28
25
|
this.router = express.Router();
|
29
26
|
}
|
30
|
-
|
31
27
|
async init() {
|
32
28
|
await this.loadConfig();
|
33
29
|
await this.loadExtends();
|
@@ -35,12 +31,6 @@ class Chan {
|
|
35
31
|
this.loadDB();
|
36
32
|
this.loadCors();
|
37
33
|
}
|
38
|
-
|
39
|
-
extend(name, fn) {
|
40
|
-
this.app.plus[name] = ()=>fn;
|
41
|
-
}
|
42
|
-
|
43
|
-
|
44
34
|
async loadConfig() {
|
45
35
|
const configPath = path.join(Chan.config.APP_PATH, "config/index.js");
|
46
36
|
if (fs.existsSync(configPath)) {
|
@@ -72,11 +62,11 @@ class Chan {
|
|
72
62
|
|
73
63
|
//数据库操作
|
74
64
|
loadDB() {
|
75
|
-
if(Chan.config?.db?.length > 0){
|
76
|
-
Chan.config.db.map((item,index) => {
|
77
|
-
if(index ==0){
|
65
|
+
if (Chan.config?.db?.length > 0) {
|
66
|
+
Chan.config.db.map((item, index) => {
|
67
|
+
if (index == 0) {
|
78
68
|
Chan.knex = createKnex(item);
|
79
|
-
}else{
|
69
|
+
} else {
|
80
70
|
Chan[`knex${index}`] = createKnex(item);
|
81
71
|
}
|
82
72
|
})
|
@@ -84,6 +74,11 @@ class Chan {
|
|
84
74
|
}
|
85
75
|
}
|
86
76
|
|
77
|
+
//解决跨域
|
78
|
+
loadCors() {
|
79
|
+
Chan.config?.cors?.origin && this.app.use(cors(Chan.config.cors));
|
80
|
+
}
|
81
|
+
|
87
82
|
//开始启动
|
88
83
|
beforeStart(cb) {
|
89
84
|
cb && cb();
|
@@ -97,14 +92,9 @@ class Chan {
|
|
97
92
|
cb && cb();
|
98
93
|
}
|
99
94
|
|
100
|
-
//解决跨域
|
101
|
-
loadCors() {
|
102
|
-
Chan.config?.cors?.origin && this.app.use(cors(Chan.config.cors));
|
103
|
-
}
|
104
|
-
|
105
95
|
// 加载插件
|
106
96
|
async loadPlugins() {
|
107
|
-
|
97
|
+
await this.loadModules("plugins");
|
108
98
|
}
|
109
99
|
|
110
100
|
/**
|
@@ -115,7 +105,7 @@ class Chan {
|
|
115
105
|
if (fs.existsSync(configPath)) {
|
116
106
|
const dirs = loadWebToEnd(Chan.config[modules]);
|
117
107
|
Chan[modules] = {};
|
118
|
-
|
108
|
+
|
119
109
|
// 先加载所有服务
|
120
110
|
for (const item of dirs) {
|
121
111
|
Chan[modules][item] = {
|
@@ -124,14 +114,13 @@ class Chan {
|
|
124
114
|
};
|
125
115
|
await this.loadServices(modules, item); // 确保每个模块的服务加载完成
|
126
116
|
}
|
127
|
-
|
117
|
+
|
128
118
|
// 加载控制器和路由
|
129
119
|
for (const item of dirs) {
|
130
120
|
await this.loadModule(modules, item); // 确保每个模块的加载完成
|
131
121
|
}
|
132
122
|
}
|
133
123
|
}
|
134
|
-
|
135
124
|
|
136
125
|
/**
|
137
126
|
* @description 加载模块,包括 controller service router
|
@@ -146,13 +135,18 @@ class Chan {
|
|
146
135
|
const dir = path.join(Chan.config.APP_PATH, modules, moduleName, type);
|
147
136
|
if (fs.existsSync(dir)) {
|
148
137
|
const files = fs.readdirSync(dir).filter(file => file.endsWith(".js"));
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
138
|
+
await Promise.all(files.map(async (file) => {
|
139
|
+
try {
|
140
|
+
const filePath = path.join(dir, file);
|
141
|
+
const fileUrl = pathToFileURL(filePath).href;
|
142
|
+
const module = await import(fileUrl);
|
143
|
+
const name = file.replace(".js", "");
|
144
|
+
Chan[modules][moduleName][type][name] = { ...bindClass(module.default) };
|
145
|
+
} catch (e) {
|
146
|
+
console.error(`加载${type}模块失败: ${file}`, e);
|
147
|
+
throw e;
|
148
|
+
}
|
149
|
+
}));
|
156
150
|
}
|
157
151
|
}
|
158
152
|
|
@@ -162,7 +156,7 @@ class Chan {
|
|
162
156
|
* @param {*} moduleName 模块名称
|
163
157
|
*/
|
164
158
|
async loadServices(modules, moduleName) {
|
165
|
-
|
159
|
+
await this.loadFiles(modules, moduleName, "service");
|
166
160
|
}
|
167
161
|
|
168
162
|
/**
|
@@ -205,7 +199,7 @@ class Chan {
|
|
205
199
|
run(cb) {
|
206
200
|
const port = Chan.config.port || "81";
|
207
201
|
this.app.listen(port, () => {
|
208
|
-
cb?cb(port):console.log(`Server is running on port ${port}`);
|
202
|
+
cb ? cb(port) : console.log(`Server is running on port ${port}`);
|
209
203
|
});
|
210
204
|
}
|
211
205
|
}
|